diff --git a/.gitignore b/.gitignore index d9f1d03040..5a4ebfdb17 100644 --- a/.gitignore +++ b/.gitignore @@ -47,12 +47,14 @@ Demo/tri_demo.out Demo/wildtype_demo.out Demo/*.log Demo/complex_demo_out.m +Demo/complex_demo_out2.m Demo/import_demo.out Demo/t1.out Demo/t2.out alternative/*.out alternative/*_out.m +alternative/*_out2.m alternative/*_demo Test/*.log @@ -73,6 +75,10 @@ Tcov/fprint.txt Doc/html +CUDA/test/googletest/* + +desktop.ini + # Do not ignore this file !.gitignore diff --git a/CMakeLists.txt b/CMakeLists.txt index 19e8e997d9..7f3b595a84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,15 +58,15 @@ if ( CMAKE_VERSION VERSION_GREATER "3.0" ) endif ( ) # version of SuiteSparse:GraphBLAS -set ( GraphBLAS_DATE "Apr 2, 2020" ) +set ( GraphBLAS_DATE "June 26, 2020" ) set ( GraphBLAS_VERSION_MAJOR 3 ) -set ( GraphBLAS_VERSION_MINOR 2 ) -set ( GraphBLAS_VERSION_SUB 2 ) +set ( GraphBLAS_VERSION_MINOR 3 ) +set ( GraphBLAS_VERSION_SUB 0 ) # GraphBLAS C API Specification version, at graphblas.org -set ( GraphBLAS_API_DATE "May 18, 2018" ) +set ( GraphBLAS_API_DATE "Sept 25, 2019" ) set ( GraphBLAS_API_VERSION_MAJOR 1 ) -set ( GraphBLAS_API_VERSION_MINOR 2 ) +set ( GraphBLAS_API_VERSION_MINOR 3 ) set ( GraphBLAS_API_VERSION_SUB 0 ) if ( CMAKE_MAJOR_VERSION GREATER 2 ) @@ -112,6 +112,12 @@ if ( GBCOMPACT ) set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGBCOMPACT=1 " ) endif ( ) +set ( GB_AVX2 false ) + +if ( GB_AVX2 ) + set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx2 -DGB_AVX2 " ) +endif ( ) + #------------------------------------------------------------------------------- # Configure Include/GraphBLAS.h and documentation with version number #------------------------------------------------------------------------------- @@ -140,9 +146,24 @@ configure_file ( include ( FindOpenMP ) include ( FindThreads ) -# FUTURE: rely on CUDA # enable_language ( CUDA ) # for nvcc, add -DGBCUDA +# set ( CMAKE_CUDA on ) +set ( CMAKE_CUDA off ) + +# LIBS = -L/usr/local/cuda/lib64 -lcudadevrt -lcudart +# LIB += -ldl -L$(CUDA_LIB_DIR) -lcuda -lcudart -lnvrtc + +if ( CMAKE_CUDA ) + message ( STATUS "CUDA enabled" ) + set ( CMAKE_CUDA_FLAG " -DGBCUDA" ) + set ( GB_CUDA graphblascuda cuda cudadevrt cudart nvrtc ) + link_directories ( "CUDA" "/usr/local/cuda/lib64" ) +else ( ) + message ( STATUS "CUDA not enabled" ) + set ( CMAKE_CUDA_FLAG " " ) + set ( GB_CUDA ) +endif ( ) #------------------------------------------------------------------------------- # report status @@ -173,6 +194,9 @@ message ( STATUS "CMAKE have OpenMP: " ${OPENMP_FOUND} ) # obtained from cblas_saxpy and cblas_daxpy. The Intel MKL can work with # libgomp, but not when libiomp is also included. +# This is fixed in the alternative/Makefile, which only loads libgomp. +# It is not yet fixed in this CMake script. + # if ( CMAKE_VERSION VERSION_GREATER "3.13" ) # # Look for the parallel 64-bit MKL BLAS by default # set ( BLA_VENDOR Intel10_64ilp ) @@ -216,6 +240,14 @@ if ( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") # cmake 2.8 workaround: gcc needs to be told to do ANSI C11. # cmake 3.0 doesn't have this problem. set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -lm -Wno-pragmas " ) + # operations may be carried out in higher precision + set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexcess-precision=fast " ) + # faster single complex multiplication and division + set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcx-limited-range " ) + # math functions do not need to report errno + set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-math-errno ") + # integer operations wrap + set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fwrapv ") # check all warnings (uncomment for development only) # set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wpedantic -Werror " ) # set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g" ) @@ -260,6 +292,8 @@ else ( ) set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_RELEASE}" ) endif ( ) +set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_CUDA_FLAG}" ) + #------------------------------------------------------------------------------- # dynamic graphblas library properties #------------------------------------------------------------------------------- @@ -352,33 +386,33 @@ endif ( ) if ( USE_OPENMP ) # use OpenMP for user thread synchronization message ( STATUS "Using OpenMP to synchronize user threads" ) - target_link_libraries ( graphblas ${M_LIB} ${OpenMP_C_LIBRARIES} ) + target_link_libraries ( graphblas ${M_LIB} ${OpenMP_C_LIBRARIES} ${GB_CUDA} ) if ( BUILD_GRB_STATIC_LIBRARY ) - target_link_libraries ( graphblas_static ${M_LIB} ${OpenMP_C_LIBRARIES} ) + target_link_libraries ( graphblas_static ${M_LIB} ${OpenMP_C_LIBRARIES} ${GB_CUDA} ) endif ( ) set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS} -DUSER_OPENMP_THREADS " ) elseif ( USE_POSIX ) # use POSIX for user thread synchronization message ( STATUS "Using POSIX pthreads to synchronize user threads" ) - target_link_libraries ( graphblas ${M_LIB} ) + target_link_libraries ( graphblas ${M_LIB} ${GB_CUDA} ) if ( BUILD_GRB_STATIC_LIBRARY ) - target_link_libraries ( graphblas_static ${M_LIB} ) + target_link_libraries ( graphblas_static ${M_LIB} ${GB_CUDA} ) endif ( ) set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -DUSER_POSIX_THREADS " ) else ( ) # use no threading at all message ( WARNING "No support for user threads; GraphBLAS will not be thread-safe" ) - target_link_libraries ( graphblas ${M_LIB} ) + target_link_libraries ( graphblas ${M_LIB} ${GB_CUDA} ) if ( BUILD_GRB_STATIC_LIBRARY ) - target_link_libraries ( graphblas_static ${M_LIB} ) + target_link_libraries ( graphblas_static ${M_LIB} ${GB_CUDA} ) endif ( ) set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSER_NO_THREADS " ) endif ( ) if ( CMAKE_THREAD_LIBS_INIT ) - target_link_libraries ( graphblas ${CMAKE_THREAD_LIBS_INIT} ) + target_link_libraries ( graphblas ${CMAKE_THREAD_LIBS_INIT} ${GB_CUDA} ) if ( BUILD_GRB_STATIC_LIBRARY ) - target_link_libraries ( graphblas_static ${CMAKE_THREAD_LIBS_INIT} ) + target_link_libraries ( graphblas_static ${CMAKE_THREAD_LIBS_INIT} ${GB_CUDA} ) endif ( ) endif ( ) @@ -386,9 +420,9 @@ if ( OPENMP_FOUND ) # use OpenMP for internal parallelism message ( STATUS "Using OpenMP for internal parallelism" ) set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}" ) - target_link_libraries ( graphblas ${M_LIB} ${OpenMP_C_LIBRARIES} ) + target_link_libraries ( graphblas ${M_LIB} ${OpenMP_C_LIBRARIES} ${GB_CUDA} ) if ( BUILD_GRB_STATIC_LIBRARY ) - target_link_libraries ( graphblas_static ${M_LIB} ${OpenMP_C_LIBRARIES} ) + target_link_libraries ( graphblas_static ${M_LIB} ${OpenMP_C_LIBRARIES} ${GB_CUDA} ) endif ( ) endif ( ) @@ -434,7 +468,7 @@ SET_TARGET_PROPERTIES ( graphblasdemo PROPERTIES SOVERSION ${GraphBLAS_VERSION_MAJOR} C_STANDARD_REQUIRED 11 ) set_property ( TARGET graphblasdemo PROPERTY C_STANDARD 11 ) -target_link_libraries ( graphblasdemo ${M_LIB} graphblas ) +target_link_libraries ( graphblasdemo ${M_LIB} graphblas ${GB_CUDA} ) if ( BUILD_GRB_STATIC_LIBRARY ) add_library ( graphblasdemo_static STATIC ${DEMO_SOURCES} ) @@ -442,7 +476,7 @@ if ( BUILD_GRB_STATIC_LIBRARY ) VERSION ${GraphBLAS_VERSION_MAJOR}.${GraphBLAS_VERSION_MINOR}.${GraphBLAS_VERSION_SUB} C_STANDARD_REQUIRED 11 ) set_property ( TARGET graphblasdemo_static PROPERTY C_STANDARD 11 ) - target_link_libraries ( graphblasdemo_static graphblas_static ) + target_link_libraries ( graphblasdemo_static graphblas_static ${GB_CUDA} ) endif ( ) #------------------------------------------------------------------------------- @@ -463,18 +497,18 @@ add_executable ( reduce_demo "Demo/Program/reduce_demo.c" ) add_executable ( import_demo "Demo/Program/import_demo.c" ) # Libraries required for Demo programs -target_link_libraries ( pagerank_demo graphblas graphblasdemo ) -target_link_libraries ( bfs_demo graphblas graphblasdemo ) -target_link_libraries ( tri_demo graphblas graphblasdemo ) -target_link_libraries ( pthread_demo graphblas graphblasdemo ) -target_link_libraries ( openmp_demo graphblas graphblasdemo ) -target_link_libraries ( mis_demo graphblas graphblasdemo ) -target_link_libraries ( complex_demo graphblas graphblasdemo ) -target_link_libraries ( kron_demo graphblas graphblasdemo ) -target_link_libraries ( simple_demo graphblasdemo ) -target_link_libraries ( wildtype_demo graphblas ) -target_link_libraries ( reduce_demo graphblas ) -target_link_libraries ( import_demo graphblas graphblasdemo ) +target_link_libraries ( pagerank_demo graphblas graphblasdemo ${GB_CUDA} ) +target_link_libraries ( bfs_demo graphblas graphblasdemo ${GB_CUDA} ) +target_link_libraries ( tri_demo graphblas graphblasdemo ${GB_CUDA} ) +target_link_libraries ( pthread_demo graphblas graphblasdemo ${GB_CUDA} ) +target_link_libraries ( openmp_demo graphblas graphblasdemo ${GB_CUDA} ) +target_link_libraries ( mis_demo graphblas graphblasdemo ${GB_CUDA} ) +target_link_libraries ( complex_demo graphblas graphblasdemo ${GB_CUDA} ) +target_link_libraries ( kron_demo graphblas graphblasdemo ${GB_CUDA} ) +target_link_libraries ( simple_demo graphblasdemo ${GB_CUDA} ) +target_link_libraries ( wildtype_demo graphblas ${GB_CUDA} ) +target_link_libraries ( reduce_demo graphblas ${GB_CUDA} ) +target_link_libraries ( import_demo graphblas graphblasdemo ${GB_CUDA} ) #------------------------------------------------------------------------------- # graphblas installation location diff --git a/Config/GraphBLAS.h.in b/Config/GraphBLAS.h.in index 52eac07f7a..48b3d86502 100644 --- a/Config/GraphBLAS.h.in +++ b/Config/GraphBLAS.h.in @@ -38,6 +38,11 @@ // attempt will be made to keep the prior GxB_* variant alongside the GrB_* // version, also for backward compatibility. +// CUDA and MKL integration are in progress. This file includes some +// defintions for related support functions and macros. These are tagged +// as DRAFT below, and are not yet documented. Do not use them; they will +// likely change when these features are added for public usage. + #ifndef GRAPHBLAS_H #define GRAPHBLAS_H @@ -205,7 +210,70 @@ #include #include -// select the user threading model: +//------------------------------------------------------------------------------ +// definitions for complex types +//------------------------------------------------------------------------------ + +// See: +// https://www.drdobbs.com/complex-arithmetic-in-the-intersection-o/184401628# + +#if defined ( __cplusplus ) + + extern "C++" { + // C++ complex types + #include + #include + #undef I + typedef std::complex GxB_FC32_t ; + typedef std::complex GxB_FC64_t ; + } + + #define GxB_CMPLXF(r,i) GxB_FC32_t(r,i) + #define GxB_CMPLX(r,i) GxB_FC64_t(r,i) + +#elif ( _MSC_VER && !__INTEL_COMPILER ) + + // Microsoft Windows complex types + #include + #undef I + typedef _Fcomplex GxB_FC32_t ; + typedef _Dcomplex GxB_FC64_t ; + + #define GxB_CMPLXF(r,i) (_FCbuild (r,i)) + #define GxB_CMPLX(r,i) ( _Cbuild (r,i)) + +#else + + // ANSI C11 complex types + #include + #undef I + typedef float complex GxB_FC32_t ; + typedef double complex GxB_FC64_t ; + + #ifndef CMPLX + // gcc 6.2 on the the Mac doesn't #define CMPLX + #define GxB_CMPLX(r,i) \ + ((GxB_FC64_t)((double)(r)) + (GxB_FC64_t)((double)(i) * _Complex_I)) + #else + // use the ANSI C11 CMPLX macro + #define GxB_CMPLX(r,i) CMPLX (r,i) + #endif + + #ifndef CMPLXF + // gcc 6.2 on the the Mac doesn't #define CMPLXF + #define GxB_CMPLXF(r,i) \ + ((GxB_FC32_t)((float)(r)) + (GxB_FC32_t)((float)(i) * _Complex_I)) + #else + // use the ANSI C11 CMPLX macro + #define GxB_CMPLXF(r,i) CMPLXF (r,i) + #endif + +#endif + +//------------------------------------------------------------------------------ +// user threading model +//------------------------------------------------------------------------------ + #if defined (USER_POSIX_THREADS) // POSIX pthreads #include @@ -214,14 +282,6 @@ // OpenMP threads: this is the default, if OpenMP is available #include -#elif defined (USER_WINDOWS_THREADS) -// Windows threads -#include - -#elif defined (USER_ANSI_THREADS) -// ANSI C11 threads -#include - #else // USER_NO_THREADS // no user threads #endif @@ -235,6 +295,15 @@ typedef uint64_t GrB_Index ; +// The largest valid dimension permitted in this implementation is 2^60. +// Matrices with that many rows and/or columns can be actually be easily +// created, particularly if they are hypersparse since in that case O(nrows) or +// O(ncols) memory is not needed. For the standard formats, O(ncols) space is +// needed for CSC and O(nrows) space is needed for CSR. For hypersparse +// matrices, the time complexity does not depend on O(nrows) or O(ncols). + +#define GxB_INDEX_MAX ((GrB_Index) (1ULL << 60)) + //------------------------------------------------------------------------------ // GraphBLAS error and informational codes //------------------------------------------------------------------------------ @@ -326,32 +395,6 @@ GrB_Info ; // The extension GxB_init does the work of GrB_init, but it also defines the // memory management functions that SuiteSparse:GraphBLAS will use internally. -// The GrB_wait ( ) function forces all pending operations to complete. -// Blocking mode is as if GrB_wait is called whenever a GraphBLAS method or -// operation returns to the user. - -// The non-blocking mode is unpredictable if user-defined functions have side -// effects or if they rely on global variables, which are not under the control -// of GraphBLAS. Suppose the user application creates a user-defined operator -// that accesses a global variable. That operator is then used in a GraphBLAS -// operation, which is left pending. If the user application then changes the -// global variable before pending operations complete, the pending operations -// will be eventually computed with this different value. - -// The non-blocking mode can have side effects if user-defined functions have -// side effects or if they rely on global variables, which are not under the -// control of GraphBLAS. Suppose the user creates a user-defined operator that -// accesses a global variable. That operator is then used in a GraphBLAS -// operation, which is left pending. If the user then changes the global -// variable before pending operations complete, the pending operations will be -// eventually computed with this different value. - -// Worse yet, a user-defined operator might be freed before it is needed to -// finish a pending operation. This causes undefined behavior. To avoid this, -// call GrB_wait before modifying any global variables relied upon by -// user-defined operators, or before freeing any user-defined types, operators, -// monoids, or semirings. - typedef enum { GrB_NONBLOCKING = 0, // methods may return with pending computations @@ -394,19 +437,32 @@ GrB_Info GxB_init // start up GraphBLAS and also define malloc, etc bool user_malloc_is_thread_safe // ADDED in V3.0: thread_safe arg ) ; -// In non-blocking mode, GraphBLAS operations need not complete until their -// results are required. GrB_wait ensures all pending operations are finished. +// GxB_cuda_init (DRAFT: in progress; do not rely on this function) +GB_PUBLIC +GrB_Info GxB_cuda_init // start up GraphBLAS for use with CUDA +( + GrB_Mode mode // blocking or non-blocking mode +) ; GB_PUBLIC -GrB_Info GrB_wait (void) ; // finish all pending computations +GrB_Info GrB_finalize (void) ; // finish GraphBLAS -// GrB_finalize does not call GrB_wait; any pending computations are abandoned. +// compile-time access to the C API Version number of this library. +#define GRB_VERSION GxB_SPEC_MAJOR +#define GRB_SUBVERSION GxB_SPEC_MINOR +// If the user program was compiled with one version of the library but linked +// with a different one later on, the compile-time version check would be +// stale. GrB_getVersion thus provides a runtime access of the C API Version. GB_PUBLIC -GrB_Info GrB_finalize (void) ; // finish GraphBLAS +GrB_Info GrB_getVersion // runtime access to C API version number +( + unsigned int *version, // returns GRB_VERSION + unsigned int *subversion // returns GRB_SUBVERSION +) ; //============================================================================== -//=== GraphBLAS sequence termination =========================================== +//=== GraphBLAS error handling ================================================= //============================================================================== // Each GraphBLAS method and operation returns a GrB_Info error code. @@ -427,28 +483,76 @@ const char *GrB_error (void) ; // return a string describing the last error // A GraphBLAS GrB_Type defines the type of scalar values that a matrix // contains, and the type of scalar operands for a unary or binary operator. -// There are eleven built-in types, and a user application can define any types -// of its own as well. The built-in types correspond to built-in types in C -// (#include #include ), and the classes in MATLAB, as -// listed below. The user application can also define new types based on any -// typedef in the C language whose values are held in a contiguous region of -// memory. +// There are 13 built-in types, and a user application can define any types of +// its own as well. The built-in types correspond to built-in types in C and +// the classes in MATLAB, as listed below. The user application can also +// define new types based on any typedef in the C language whose values are +// held in a contiguous region of memory. typedef struct GB_Type_opaque *GrB_Type ; -// GraphBLAS predefined types and the counterparts in pure C and in MATLAB +// GraphBLAS predefined types and their counterparts in pure C and in MATLAB GB_PUBLIC GrB_Type - GrB_BOOL , // in C: bool in MATLAB: logical - GrB_INT8 , // in C: int8_t in MATLAB: int8 - GrB_UINT8 , // in C: uint8_t in MATLAB: uint8 - GrB_INT16 , // in C: int16_t in MATLAB: int16 - GrB_UINT16 , // in C: uint16_t in MATLAB: uint16 - GrB_INT32 , // in C: int32_t in MATLAB: int32 - GrB_UINT32 , // in C: uint32_t in MATLAB: uint32 - GrB_INT64 , // in C: int64_t in MATLAB: int64 - GrB_UINT64 , // in C: uint64_t in MATLAB: uint64 - GrB_FP32 , // in C: float in MATLAB: single - GrB_FP64 ; // in C: double in MATLAB: double + GrB_BOOL , // in C: bool in MATLAB: logical + GrB_INT8 , // in C: int8_t in MATLAB: int8 + GrB_INT16 , // in C: int16_t in MATLAB: int16 + GrB_INT32 , // in C: int32_t in MATLAB: int32 + GrB_INT64 , // in C: int64_t in MATLAB: int64 + GrB_UINT8 , // in C: uint8_t in MATLAB: uint8 + GrB_UINT16 , // in C: uint16_t in MATLAB: uint16 + GrB_UINT32 , // in C: uint32_t in MATLAB: uint32 + GrB_UINT64 , // in C: uint64_t in MATLAB: uint64 + GrB_FP32 , // in C: float in MATLAB: single + GrB_FP64 , // in C: double in MATLAB: double + GxB_FC32 , // in C: float complex in MATLAB: single complex + GxB_FC64 ; // in C: double complex in MATLAB: double complex + +// SPEC: complex types are an extension to the spec. + +//------------------------------------------------------------------------------ +// GB_ helper macro for polymorphic functions +//------------------------------------------------------------------------------ + +// This macro is not intended for use outside this file. It provides the case +// statements for the _Generic macros used in polymorphic functions, to select +// a function based on one of the pre-defined types listed above, or a +// user-defined type. + +#if GxB_STDC_VERSION >= 201112L +#define GB_(p,prefix,func) \ + const bool p : prefix ## _ ## func ## _BOOL , \ + bool p : prefix ## _ ## func ## _BOOL , \ + const int8_t p : prefix ## _ ## func ## _INT8 , \ + int8_t p : prefix ## _ ## func ## _INT8 , \ + const int16_t p : prefix ## _ ## func ## _INT16 , \ + int16_t p : prefix ## _ ## func ## _INT16 , \ + const int32_t p : prefix ## _ ## func ## _INT32 , \ + int32_t p : prefix ## _ ## func ## _INT32 , \ + const int64_t p : prefix ## _ ## func ## _INT64 , \ + int64_t p : prefix ## _ ## func ## _INT64 , \ + const uint8_t p : prefix ## _ ## func ## _UINT8 , \ + uint8_t p : prefix ## _ ## func ## _UINT8 , \ + const uint16_t p : prefix ## _ ## func ## _UINT16 , \ + uint16_t p : prefix ## _ ## func ## _UINT16 , \ + const uint32_t p : prefix ## _ ## func ## _UINT32 , \ + uint32_t p : prefix ## _ ## func ## _UINT32 , \ + const uint64_t p : prefix ## _ ## func ## _UINT64 , \ + uint64_t p : prefix ## _ ## func ## _UINT64 , \ + const float p : prefix ## _ ## func ## _FP32 , \ + float p : prefix ## _ ## func ## _FP32 , \ + const double p : prefix ## _ ## func ## _FP64 , \ + double p : prefix ## _ ## func ## _FP64 , \ + const GxB_FC32_t p : GxB ## _ ## func ## _FC32 , \ + GxB_FC32_t p : GxB ## _ ## func ## _FC32 , \ + const GxB_FC64_t p : GxB ## _ ## func ## _FC64 , \ + GxB_FC64_t p : GxB ## _ ## func ## _FC64 , \ + const void * : prefix ## _ ## func ## _UDT , \ + void * : prefix ## _ ## func ## _UDT +#endif + +//------------------------------------------------------------------------------ +// GrB_Type_new: create a new type +//------------------------------------------------------------------------------ // GrB_Type_new is implemented both as a macro and a function. Both are // user-callable. The default is to use the macro, since this allows the name @@ -517,12 +621,9 @@ GrB_Info GrB_Type_free // free a user-defined type // GraphBLAS defines built-in unary and binary operators, and the user may also // define new ones via function pointers. When a user function z=f(x,y) or // z=f(x) is called by GraphBLAS, the pointers x, y, and z are guaranteed to be -// non-NULL and to point to unique valid space of the expected type. - -// SuiteSparse:GraphBLAS provides 278 built-in binary operators z=f(x,y) and 45 -// built-in unary operators z=f(x) that operate on the 11 built-in types. -// Built-in types are statically allocated and need not be freed when the -// application finishes. +// non-NULL and to point to unique valid space of the expected type. Built-in +// types are statically allocated and need not be freed when the application +// finishes. //------------------------------------------------------------------------------ // unary operators @@ -542,49 +643,180 @@ typedef struct GB_UnaryOp_opaque *GrB_UnaryOp ; // built-in unary operators, z = f(x) //------------------------------------------------------------------------------ -// There are 67 unary operators: 6 kinds * 11 types and GrB_LNOT. - -// SPEC: ONE and ABS unary operators are extensions to the spec -// as are the LNOT_TYPE operators. - GB_PUBLIC GrB_UnaryOp - // For these three functions z=f(x), z and x have the same type. + // For these functions z=f(x), z and x have the same type. // The suffix in the name is the type of x and z. // z = x z = -x z = 1/x z = ! (x != 0) // identity additive multiplicative logical // inverse inverse negation GrB_IDENTITY_BOOL, GrB_AINV_BOOL, GrB_MINV_BOOL, GxB_LNOT_BOOL, GrB_IDENTITY_INT8, GrB_AINV_INT8, GrB_MINV_INT8, GxB_LNOT_INT8, - GrB_IDENTITY_UINT8, GrB_AINV_UINT8, GrB_MINV_UINT8, GxB_LNOT_UINT8, GrB_IDENTITY_INT16, GrB_AINV_INT16, GrB_MINV_INT16, GxB_LNOT_INT16, - GrB_IDENTITY_UINT16, GrB_AINV_UINT16, GrB_MINV_UINT16, GxB_LNOT_UINT16, GrB_IDENTITY_INT32, GrB_AINV_INT32, GrB_MINV_INT32, GxB_LNOT_INT32, - GrB_IDENTITY_UINT32, GrB_AINV_UINT32, GrB_MINV_UINT32, GxB_LNOT_UINT32, GrB_IDENTITY_INT64, GrB_AINV_INT64, GrB_MINV_INT64, GxB_LNOT_INT64, + GrB_IDENTITY_UINT8, GrB_AINV_UINT8, GrB_MINV_UINT8, GxB_LNOT_UINT8, + GrB_IDENTITY_UINT16, GrB_AINV_UINT16, GrB_MINV_UINT16, GxB_LNOT_UINT16, + GrB_IDENTITY_UINT32, GrB_AINV_UINT32, GrB_MINV_UINT32, GxB_LNOT_UINT32, GrB_IDENTITY_UINT64, GrB_AINV_UINT64, GrB_MINV_UINT64, GxB_LNOT_UINT64, GrB_IDENTITY_FP32, GrB_AINV_FP32, GrB_MINV_FP32, GxB_LNOT_FP32, GrB_IDENTITY_FP64, GrB_AINV_FP64, GrB_MINV_FP64, GxB_LNOT_FP64, - - // z = 1 z = abs(x) - // one absolute value - // - GxB_ONE_BOOL, GxB_ABS_BOOL, - GxB_ONE_INT8, GxB_ABS_INT8, - GxB_ONE_UINT8, GxB_ABS_UINT8, - GxB_ONE_INT16, GxB_ABS_INT16, - GxB_ONE_UINT16, GxB_ABS_UINT16, - GxB_ONE_INT32, GxB_ABS_INT32, - GxB_ONE_UINT32, GxB_ABS_UINT32, - GxB_ONE_INT64, GxB_ABS_INT64, - GxB_ONE_UINT64, GxB_ABS_UINT64, - GxB_ONE_FP32, GxB_ABS_FP32, - GxB_ONE_FP64, GxB_ABS_FP64, - - // Boolean negation, z = !x, where both x and x are boolean. There is no + // complex unary operators: + GxB_IDENTITY_FC32, GxB_AINV_FC32, GxB_MINV_FC32, // no LNOT + GxB_IDENTITY_FC64, GxB_AINV_FC64, GxB_MINV_FC64, // for complex + + // z = 1 z = abs(x) z = bnot(x) z = signum + // one absolute value bitwise negation + GxB_ONE_BOOL, GrB_ABS_BOOL, + GxB_ONE_INT8, GrB_ABS_INT8, GrB_BNOT_INT8, + GxB_ONE_INT16, GrB_ABS_INT16, GrB_BNOT_INT16, + GxB_ONE_INT32, GrB_ABS_INT32, GrB_BNOT_INT32, + GxB_ONE_INT64, GrB_ABS_INT64, GrB_BNOT_INT64, + GxB_ONE_UINT8, GrB_ABS_UINT8, GrB_BNOT_UINT8, + GxB_ONE_UINT16, GrB_ABS_UINT16, GrB_BNOT_UINT16, + GxB_ONE_UINT32, GrB_ABS_UINT32, GrB_BNOT_UINT32, + GxB_ONE_UINT64, GrB_ABS_UINT64, GrB_BNOT_UINT64, + GxB_ONE_FP32, GrB_ABS_FP32, + GxB_ONE_FP64, GrB_ABS_FP64, + // complex unary operators: + GxB_ONE_FC32, // for complex types, z = abs(x) + GxB_ONE_FC64, // is real; listed below. + + // Boolean negation, z = !x, where both z and x are boolean. There is no // suffix since z and x are only boolean. This operator is identical to // GxB_LNOT_BOOL; it just has a different name. GrB_LNOT ; +//------------------------------------------------------------------------------ +// operators for backward compatibilty +//------------------------------------------------------------------------------ + +// Now with GrB* names in the current specification. Kept for backward +// compatibility. + +GB_PUBLIC GrB_UnaryOp + + // z = abs(x) + GxB_ABS_BOOL, + GxB_ABS_INT8, + GxB_ABS_INT16, + GxB_ABS_INT32, + GxB_ABS_INT64, + GxB_ABS_UINT8, + GxB_ABS_UINT16, + GxB_ABS_UINT32, + GxB_ABS_UINT64, + GxB_ABS_FP32, + GxB_ABS_FP64 ; + +//------------------------------------------------------------------------------ +// Unary operators for floating-point types only +//------------------------------------------------------------------------------ + +// The following floating-point unary operators and their ANSI C11 equivalents, +// are only defined for floating-point (real and complex) types. + +GB_PUBLIC GrB_UnaryOp + + //-------------------------------------------------------------------------- + // z = f(x) where z and x have the same type (all 4 floating-point types) + //-------------------------------------------------------------------------- + + // z = sqrt (x) z = log (x) z = exp (x) z = log2 (x) + GxB_SQRT_FP32, GxB_LOG_FP32, GxB_EXP_FP32, GxB_LOG2_FP32, + GxB_SQRT_FP64, GxB_LOG_FP64, GxB_EXP_FP64, GxB_LOG2_FP64, + GxB_SQRT_FC32, GxB_LOG_FC32, GxB_EXP_FC32, GxB_LOG2_FC32, + GxB_SQRT_FC64, GxB_LOG_FC64, GxB_EXP_FC64, GxB_LOG2_FC64, + + // z = sin (x) z = cos (x) z = tan (x) + GxB_SIN_FP32, GxB_COS_FP32, GxB_TAN_FP32, + GxB_SIN_FP64, GxB_COS_FP64, GxB_TAN_FP64, + GxB_SIN_FC32, GxB_COS_FC32, GxB_TAN_FC32, + GxB_SIN_FC64, GxB_COS_FC64, GxB_TAN_FC64, + + // z = acos (x) z = asin (x) z = atan (x) + GxB_ACOS_FP32, GxB_ASIN_FP32, GxB_ATAN_FP32, + GxB_ACOS_FP64, GxB_ASIN_FP64, GxB_ATAN_FP64, + GxB_ACOS_FC32, GxB_ASIN_FC32, GxB_ATAN_FC32, + GxB_ACOS_FC64, GxB_ASIN_FC64, GxB_ATAN_FC64, + + // z = sinh (x) z = cosh (x) z = tanh (x) + GxB_SINH_FP32, GxB_COSH_FP32, GxB_TANH_FP32, + GxB_SINH_FP64, GxB_COSH_FP64, GxB_TANH_FP64, + GxB_SINH_FC32, GxB_COSH_FC32, GxB_TANH_FC32, + GxB_SINH_FC64, GxB_COSH_FC64, GxB_TANH_FC64, + + // z = acosh (x) z = asinh (x) z = atanh (x) z = signum (x) + GxB_ACOSH_FP32, GxB_ASINH_FP32, GxB_ATANH_FP32, GxB_SIGNUM_FP32, + GxB_ACOSH_FP64, GxB_ASINH_FP64, GxB_ATANH_FP64, GxB_SIGNUM_FP64, + GxB_ACOSH_FC32, GxB_ASINH_FC32, GxB_ATANH_FC32, GxB_SIGNUM_FC32, + GxB_ACOSH_FC64, GxB_ASINH_FC64, GxB_ATANH_FC64, GxB_SIGNUM_FC64, + + // z = ceil (x) z = floor (x) z = round (x) z = trunc (x) + GxB_CEIL_FP32, GxB_FLOOR_FP32, GxB_ROUND_FP32, GxB_TRUNC_FP32, + GxB_CEIL_FP64, GxB_FLOOR_FP64, GxB_ROUND_FP64, GxB_TRUNC_FP64, + GxB_CEIL_FC32, GxB_FLOOR_FC32, GxB_ROUND_FC32, GxB_TRUNC_FC32, + GxB_CEIL_FC64, GxB_FLOOR_FC64, GxB_ROUND_FC64, GxB_TRUNC_FC64, + + // z = exp2 (x) z = expm1 (x) z = log10 (x) z = log1p (x) + GxB_EXP2_FP32, GxB_EXPM1_FP32, GxB_LOG10_FP32, GxB_LOG1P_FP32, + GxB_EXP2_FP64, GxB_EXPM1_FP64, GxB_LOG10_FP64, GxB_LOG1P_FP64, + GxB_EXP2_FC32, GxB_EXPM1_FC32, GxB_LOG10_FC32, GxB_LOG1P_FC32, + GxB_EXP2_FC64, GxB_EXPM1_FC64, GxB_LOG10_FC64, GxB_LOG1P_FC64, + + //-------------------------------------------------------------------------- + // z = f(x) where z and x are the same type (floating-point real only) + //-------------------------------------------------------------------------- + + // z = lgamma (x) z = tgamma (x) z = erf (x) z = erfc (x) + GxB_LGAMMA_FP32, GxB_TGAMMA_FP32, GxB_ERF_FP32, GxB_ERFC_FP32, + GxB_LGAMMA_FP64, GxB_TGAMMA_FP64, GxB_ERF_FP64, GxB_ERFC_FP64, + + // frexpx and frexpe return the mantissa and exponent, respectively, + // from the ANSI C11 frexp function. The exponent is returned as a + // floating-point value, not an integer. + + // z = frexpx (x) z = frexpe (x) + GxB_FREXPX_FP32, GxB_FREXPE_FP32, + GxB_FREXPX_FP64, GxB_FREXPE_FP64, + + //-------------------------------------------------------------------------- + // z = f(x) where z and x are the same type (complex only) + //-------------------------------------------------------------------------- + + // z = conj (x) + GxB_CONJ_FC32, + GxB_CONJ_FC64, + + //-------------------------------------------------------------------------- + // z = f(x) where z is real and x is complex: + //-------------------------------------------------------------------------- + + // z = creal (x) z = cimag (x) z = carg (x) z = abs (x) + GxB_CREAL_FC32, GxB_CIMAG_FC32, GxB_CARG_FC32, GxB_ABS_FC32, + GxB_CREAL_FC64, GxB_CIMAG_FC64, GxB_CARG_FC64, GxB_ABS_FC64, + + //-------------------------------------------------------------------------- + // z = f(x) where z is bool and x is any floating-point type + //-------------------------------------------------------------------------- + + // z = isinf (x) + GxB_ISINF_FP32, + GxB_ISINF_FP64, + GxB_ISINF_FC32, // isinf (creal (x)) || isinf (cimag (x)) + GxB_ISINF_FC64, // isinf (creal (x)) || isinf (cimag (x)) + + // z = isnan (x) + GxB_ISNAN_FP32, + GxB_ISNAN_FP64, + GxB_ISNAN_FC32, // isnan (creal (x)) || isnan (cimag (x)) + GxB_ISNAN_FC64, // isnan (creal (x)) || isnan (cimag (x)) + + // z = isfinite (x) + GxB_ISFINITE_FP32, + GxB_ISFINITE_FP64, + GxB_ISFINITE_FC32, // isfinite (real (x)) && isfinite (cimag (x)) + GxB_ISFINITE_FC64 ; // isfinite (real (x)) && isfinite (cimag (x)) + //------------------------------------------------------------------------------ // methods for unary operators //------------------------------------------------------------------------------ @@ -659,189 +891,272 @@ GrB_Info GrB_UnaryOp_free // free a user-created unary operator typedef struct GB_BinaryOp_opaque *GrB_BinaryOp ; //------------------------------------------------------------------------------ -// built-in binary operators, z = f(x,y) +// built-in binary operators, z = f(x,y), where x,y,z all have the same type //------------------------------------------------------------------------------ -// There are three sets of built-in binary operators. For the first set of -// 21 kinds of operators, x,y,z all have the same type, and they are available -// for all 11 types, for a total of 21*21 = 231 operators. All of them have -// a "_TYPE" suffix that denotes the type of x,y,z: - -// 12 general: FIRST, SECOND, MIN, MAX, PLUS, MINUS, RMINUS, TIMES, -// DIV, RDIV, PAIR, ANY -// 6 comparison: ISEQ, ISNE, ISGT, ISLT, ISGE, ISLE -// 3 logical: LOR, LAND, LXOR - -// For the second set, there are 6 comparison operators where, x,y have the -// same type but z is always boolean, for a total of 6*11 = 66 operators. -// All of them have a "_TYPE" suffix that denotes the type of x,y (not z): - -// 6 comparison: EQ, NE, GT, LT, GE, LE - -// The final set of operators is for boolean x,y,z only, and they have no -// suffix: - -// 3 logical: LOR, LAND, LXOR - -// Thus there are 231+66+3 = 300 built-in binary operators. Some are redundant -// but are included to keep the name space of operators uniform. - -// For 12 binary operators z=f(x,y), x, y, and z are all the same type: -// FIRST, SECOND, MIN, MAX, PLUS, MINUS, RMINUS, TIMES, DIV, RDIV, PAIR, ANY, -// for all 11 types. - GB_PUBLIC GrB_BinaryOp - // z = x z = y z = min(x,y) z = max (x,y) - GrB_FIRST_BOOL, GrB_SECOND_BOOL, GrB_MIN_BOOL, GrB_MAX_BOOL, - GrB_FIRST_INT8, GrB_SECOND_INT8, GrB_MIN_INT8, GrB_MAX_INT8, - GrB_FIRST_UINT8, GrB_SECOND_UINT8, GrB_MIN_UINT8, GrB_MAX_UINT8, - GrB_FIRST_INT16, GrB_SECOND_INT16, GrB_MIN_INT16, GrB_MAX_INT16, - GrB_FIRST_UINT16, GrB_SECOND_UINT16, GrB_MIN_UINT16, GrB_MAX_UINT16, - GrB_FIRST_INT32, GrB_SECOND_INT32, GrB_MIN_INT32, GrB_MAX_INT32, - GrB_FIRST_UINT32, GrB_SECOND_UINT32, GrB_MIN_UINT32, GrB_MAX_UINT32, - GrB_FIRST_INT64, GrB_SECOND_INT64, GrB_MIN_INT64, GrB_MAX_INT64, - GrB_FIRST_UINT64, GrB_SECOND_UINT64, GrB_MIN_UINT64, GrB_MAX_UINT64, - GrB_FIRST_FP32, GrB_SECOND_FP32, GrB_MIN_FP32, GrB_MAX_FP32, - GrB_FIRST_FP64, GrB_SECOND_FP64, GrB_MIN_FP64, GrB_MAX_FP64, + + // operators for all 13 types (including complex): + + // z = x z = y z = pow (x,y) + GrB_FIRST_BOOL, GrB_SECOND_BOOL, GxB_POW_BOOL, + GrB_FIRST_INT8, GrB_SECOND_INT8, GxB_POW_INT8, + GrB_FIRST_INT16, GrB_SECOND_INT16, GxB_POW_INT16, + GrB_FIRST_INT32, GrB_SECOND_INT32, GxB_POW_INT32, + GrB_FIRST_INT64, GrB_SECOND_INT64, GxB_POW_INT64, + GrB_FIRST_UINT8, GrB_SECOND_UINT8, GxB_POW_UINT8, + GrB_FIRST_UINT16, GrB_SECOND_UINT16, GxB_POW_UINT16, + GrB_FIRST_UINT32, GrB_SECOND_UINT32, GxB_POW_UINT32, + GrB_FIRST_UINT64, GrB_SECOND_UINT64, GxB_POW_UINT64, + GrB_FIRST_FP32, GrB_SECOND_FP32, GxB_POW_FP32, + GrB_FIRST_FP64, GrB_SECOND_FP64, GxB_POW_FP64, + // complex: + GxB_FIRST_FC32, GxB_SECOND_FC32, GxB_POW_FC32, + GxB_FIRST_FC64, GxB_SECOND_FC64, GxB_POW_FC64, // z = x+y z = x-y z = x*y z = x/y GrB_PLUS_BOOL, GrB_MINUS_BOOL, GrB_TIMES_BOOL, GrB_DIV_BOOL, GrB_PLUS_INT8, GrB_MINUS_INT8, GrB_TIMES_INT8, GrB_DIV_INT8, - GrB_PLUS_UINT8, GrB_MINUS_UINT8, GrB_TIMES_UINT8, GrB_DIV_UINT8, GrB_PLUS_INT16, GrB_MINUS_INT16, GrB_TIMES_INT16, GrB_DIV_INT16, - GrB_PLUS_UINT16, GrB_MINUS_UINT16, GrB_TIMES_UINT16, GrB_DIV_UINT16, GrB_PLUS_INT32, GrB_MINUS_INT32, GrB_TIMES_INT32, GrB_DIV_INT32, - GrB_PLUS_UINT32, GrB_MINUS_UINT32, GrB_TIMES_UINT32, GrB_DIV_UINT32, GrB_PLUS_INT64, GrB_MINUS_INT64, GrB_TIMES_INT64, GrB_DIV_INT64, + GrB_PLUS_UINT8, GrB_MINUS_UINT8, GrB_TIMES_UINT8, GrB_DIV_UINT8, + GrB_PLUS_UINT16, GrB_MINUS_UINT16, GrB_TIMES_UINT16, GrB_DIV_UINT16, + GrB_PLUS_UINT32, GrB_MINUS_UINT32, GrB_TIMES_UINT32, GrB_DIV_UINT32, GrB_PLUS_UINT64, GrB_MINUS_UINT64, GrB_TIMES_UINT64, GrB_DIV_UINT64, GrB_PLUS_FP32, GrB_MINUS_FP32, GrB_TIMES_FP32, GrB_DIV_FP32, GrB_PLUS_FP64, GrB_MINUS_FP64, GrB_TIMES_FP64, GrB_DIV_FP64, + // complex: + GxB_PLUS_FC32, GxB_MINUS_FC32, GxB_TIMES_FC32, GxB_DIV_FC32, + GxB_PLUS_FC64, GxB_MINUS_FC64, GxB_TIMES_FC64, GxB_DIV_FC64, - // z = y-x z = y/x z = 1 z = pick(x,y) + // z = y-x z = y/x z = 1 z = any(x,y) GxB_RMINUS_BOOL, GxB_RDIV_BOOL, GxB_PAIR_BOOL, GxB_ANY_BOOL, GxB_RMINUS_INT8, GxB_RDIV_INT8, GxB_PAIR_INT8, GxB_ANY_INT8, - GxB_RMINUS_UINT8, GxB_RDIV_UINT8, GxB_PAIR_UINT8, GxB_ANY_UINT8, GxB_RMINUS_INT16, GxB_RDIV_INT16, GxB_PAIR_INT16, GxB_ANY_INT16, - GxB_RMINUS_UINT16, GxB_RDIV_UINT16, GxB_PAIR_UINT16, GxB_ANY_UINT16, GxB_RMINUS_INT32, GxB_RDIV_INT32, GxB_PAIR_INT32, GxB_ANY_INT32, - GxB_RMINUS_UINT32, GxB_RDIV_UINT32, GxB_PAIR_UINT32, GxB_ANY_UINT32, GxB_RMINUS_INT64, GxB_RDIV_INT64, GxB_PAIR_INT64, GxB_ANY_INT64, + GxB_RMINUS_UINT8, GxB_RDIV_UINT8, GxB_PAIR_UINT8, GxB_ANY_UINT8, + GxB_RMINUS_UINT16, GxB_RDIV_UINT16, GxB_PAIR_UINT16, GxB_ANY_UINT16, + GxB_RMINUS_UINT32, GxB_RDIV_UINT32, GxB_PAIR_UINT32, GxB_ANY_UINT32, GxB_RMINUS_UINT64, GxB_RDIV_UINT64, GxB_PAIR_UINT64, GxB_ANY_UINT64, GxB_RMINUS_FP32, GxB_RDIV_FP32, GxB_PAIR_FP32, GxB_ANY_FP32, GxB_RMINUS_FP64, GxB_RDIV_FP64, GxB_PAIR_FP64, GxB_ANY_FP64, + // complex: + GxB_RMINUS_FC32, GxB_RDIV_FC32, GxB_PAIR_FC32, GxB_ANY_FC32, + GxB_RMINUS_FC64, GxB_RDIV_FC64, GxB_PAIR_FC64, GxB_ANY_FC64, + + // The GxB_IS* comparison operators z=f(x,y) return the same type as their + // inputs. Each of them compute z = (x OP y), where x, y, and z all have + // the same type. The value z is either 1 for true or 0 for false, but it + // is a value with the same type as x and y. Z is not bool (unless x and y + // are also bool). These operators compute the same thing as the 6 sets of + // EQ, NE, GT, LT, GE, and LE operators. They just return their result z + // as the same type as x and y, instead of returning a value z that is + // boolean. Since their ztype is non-boolean, they can be used as multiply + // operators in a semring with non-boolean monoids (PLUS, for example). + + // z = (x == y) z = (x != y) + GxB_ISEQ_BOOL, GxB_ISNE_BOOL, + GxB_ISEQ_INT8, GxB_ISNE_INT8, + GxB_ISEQ_INT16, GxB_ISNE_INT16, + GxB_ISEQ_INT32, GxB_ISNE_INT32, + GxB_ISEQ_INT64, GxB_ISNE_INT64, + GxB_ISEQ_UINT8, GxB_ISNE_UINT8, + GxB_ISEQ_UINT16, GxB_ISNE_UINT16, + GxB_ISEQ_UINT32, GxB_ISNE_UINT32, + GxB_ISEQ_UINT64, GxB_ISNE_UINT64, + GxB_ISEQ_FP32, GxB_ISNE_FP32, + GxB_ISEQ_FP64, GxB_ISNE_FP64, + // complex: + GxB_ISEQ_FC32, GxB_ISNE_FC32, + GxB_ISEQ_FC64, GxB_ISNE_FC64, + + // The following operators are not defined for complex types: + + // z = (x > y) z = (x < y) z = (x >= y) z = (x <= y) + GxB_ISGT_BOOL, GxB_ISLT_BOOL, GxB_ISGE_BOOL, GxB_ISLE_BOOL, + GxB_ISGT_INT8, GxB_ISLT_INT8, GxB_ISGE_INT8, GxB_ISLE_INT8, + GxB_ISGT_INT16, GxB_ISLT_INT16, GxB_ISGE_INT16, GxB_ISLE_INT16, + GxB_ISGT_INT32, GxB_ISLT_INT32, GxB_ISGE_INT32, GxB_ISLE_INT32, + GxB_ISGT_INT64, GxB_ISLT_INT64, GxB_ISGE_INT64, GxB_ISLE_INT64, + GxB_ISGT_UINT8, GxB_ISLT_UINT8, GxB_ISGE_UINT8, GxB_ISLE_UINT8, + GxB_ISGT_UINT16, GxB_ISLT_UINT16, GxB_ISGE_UINT16, GxB_ISLE_UINT16, + GxB_ISGT_UINT32, GxB_ISLT_UINT32, GxB_ISGE_UINT32, GxB_ISLE_UINT32, + GxB_ISGT_UINT64, GxB_ISLT_UINT64, GxB_ISGE_UINT64, GxB_ISLE_UINT64, + GxB_ISGT_FP32, GxB_ISLT_FP32, GxB_ISGE_FP32, GxB_ISLE_FP32, + GxB_ISGT_FP64, GxB_ISLT_FP64, GxB_ISGE_FP64, GxB_ISLE_FP64, + + // z = min(x,y) z = max (x,y) + GrB_MIN_BOOL, GrB_MAX_BOOL, + GrB_MIN_INT8, GrB_MAX_INT8, + GrB_MIN_INT16, GrB_MAX_INT16, + GrB_MIN_INT32, GrB_MAX_INT32, + GrB_MIN_INT64, GrB_MAX_INT64, + GrB_MIN_UINT8, GrB_MAX_UINT8, + GrB_MIN_UINT16, GrB_MAX_UINT16, + GrB_MIN_UINT32, GrB_MAX_UINT32, + GrB_MIN_UINT64, GrB_MAX_UINT64, + GrB_MIN_FP32, GrB_MAX_FP32, + GrB_MIN_FP64, GrB_MAX_FP64, + + // Binary operators for each of the 11 real types: + + // The operators convert non-boolean types internally to boolean and return + // a value 1 or 0 in the same type, for true or false. Each computes z = + // ((x != 0) OP (y != 0)), where x, y, and z all the same type. These + // operators are useful as multiplicative operators when combined with + // non-boolean monoids of the same type. -// Six comparison operators z=f(x,y) return the same type as their inputs. -// Each of them compute z = (x OP y), where x, y, and z all have the same type. -// The value z is either 1 for true or 0 for false, but it is a value with the -// same type as x and y. Z is not bool (unless x and y are also bool). These -// operators compute the same thing as the 6 sets of EQ, NE, GT, LT, GE, and LE -// operators. They just return their result z as the same type as x and y, -// instead of returning a value z that is boolean. Since their ztype is -// non-boolean, they can be used as multiply operators in a semring with -// non-boolean monoids (PLUS, for example). + // z = (x || y) z = (x && y) z = (x != y) + GxB_LOR_BOOL, GxB_LAND_BOOL, GxB_LXOR_BOOL, + GxB_LOR_INT8, GxB_LAND_INT8, GxB_LXOR_INT8, + GxB_LOR_INT16, GxB_LAND_INT16, GxB_LXOR_INT16, + GxB_LOR_INT32, GxB_LAND_INT32, GxB_LXOR_INT32, + GxB_LOR_INT64, GxB_LAND_INT64, GxB_LXOR_INT64, + GxB_LOR_UINT8, GxB_LAND_UINT8, GxB_LXOR_UINT8, + GxB_LOR_UINT16, GxB_LAND_UINT16, GxB_LXOR_UINT16, + GxB_LOR_UINT32, GxB_LAND_UINT32, GxB_LXOR_UINT32, + GxB_LOR_UINT64, GxB_LAND_UINT64, GxB_LXOR_UINT64, + GxB_LOR_FP32, GxB_LAND_FP32, GxB_LXOR_FP32, + GxB_LOR_FP64, GxB_LAND_FP64, GxB_LXOR_FP64, - // z = (x == y) z = (x != y) z = (x > y) z = (x < y) - GxB_ISEQ_BOOL, GxB_ISNE_BOOL, GxB_ISGT_BOOL, GxB_ISLT_BOOL, - GxB_ISEQ_INT8, GxB_ISNE_INT8, GxB_ISGT_INT8, GxB_ISLT_INT8, - GxB_ISEQ_UINT8, GxB_ISNE_UINT8, GxB_ISGT_UINT8, GxB_ISLT_UINT8, - GxB_ISEQ_INT16, GxB_ISNE_INT16, GxB_ISGT_INT16, GxB_ISLT_INT16, - GxB_ISEQ_UINT16, GxB_ISNE_UINT16, GxB_ISGT_UINT16, GxB_ISLT_UINT16, - GxB_ISEQ_INT32, GxB_ISNE_INT32, GxB_ISGT_INT32, GxB_ISLT_INT32, - GxB_ISEQ_UINT32, GxB_ISNE_UINT32, GxB_ISGT_UINT32, GxB_ISLT_UINT32, - GxB_ISEQ_INT64, GxB_ISNE_INT64, GxB_ISGT_INT64, GxB_ISLT_INT64, - GxB_ISEQ_UINT64, GxB_ISNE_UINT64, GxB_ISGT_UINT64, GxB_ISLT_UINT64, - GxB_ISEQ_FP32, GxB_ISNE_FP32, GxB_ISGT_FP32, GxB_ISLT_FP32, - GxB_ISEQ_FP64, GxB_ISNE_FP64, GxB_ISGT_FP64, GxB_ISLT_FP64, + // Binary operators operate only on boolean types: LOR, LAND, LXOR, and + // LXNOR. The naming convention differs (_BOOL is not appended to the + // name). They are the same as GxB_LOR_BOOL, GxB_LAND_BOOL, and + // GxB_LXOR_BOOL, and GrB_EQ_BOOL, respectively. - // z = (x >= y) z = (x <= y) - GxB_ISGE_BOOL, GxB_ISLE_BOOL, - GxB_ISGE_INT8, GxB_ISLE_INT8, - GxB_ISGE_UINT8, GxB_ISLE_UINT8, - GxB_ISGE_INT16, GxB_ISLE_INT16, - GxB_ISGE_UINT16, GxB_ISLE_UINT16, - GxB_ISGE_INT32, GxB_ISLE_INT32, - GxB_ISGE_UINT32, GxB_ISLE_UINT32, - GxB_ISGE_INT64, GxB_ISLE_INT64, - GxB_ISGE_UINT64, GxB_ISLE_UINT64, - GxB_ISGE_FP32, GxB_ISLE_FP32, - GxB_ISGE_FP64, GxB_ISLE_FP64, - -// Six comparison operators z=f(x,y) return their result as boolean, but where -// x and y have the same type (any one of the 11 built-in types). The suffix -// in their names refers to the type of x and y since z is always boolean. If -// used as multiply operators in a semiring, they can only be combined with -// boolean monoids. The _BOOL versions of these operators give the same -// results as their IS*_BOOL counterparts. + // z = (x || y) z = (x && y) z = (x != y) z = (x == y) + GrB_LOR, GrB_LAND, GrB_LXOR, GrB_LXNOR, + + // Operators for floating-point reals: + + // z = atan2(x,y) z = hypot(x,y) z = fmod(x,y) z = remainder(x,y) + GxB_ATAN2_FP32, GxB_HYPOT_FP32, GxB_FMOD_FP32, GxB_REMAINDER_FP32, + GxB_ATAN2_FP64, GxB_HYPOT_FP64, GxB_FMOD_FP64, GxB_REMAINDER_FP64, + + // z = ldexp(x,y) z = copysign (x,y) + GxB_LDEXP_FP32, GxB_COPYSIGN_FP32, + GxB_LDEXP_FP64, GxB_COPYSIGN_FP64, + + // Bitwise operations on signed and unsigned integers: note that + // bitwise operations on signed integers can lead to different results, + // depending on your compiler; results are implementation-defined. + + // z = (x | y) z = (x & y) z = (x ^ y) z = ~(x ^ y) + GrB_BOR_INT8, GrB_BAND_INT8, GrB_BXOR_INT8, GrB_BXNOR_INT8, + GrB_BOR_INT16, GrB_BAND_INT16, GrB_BXOR_INT16, GrB_BXNOR_INT16, + GrB_BOR_INT32, GrB_BAND_INT32, GrB_BXOR_INT32, GrB_BXNOR_INT32, + GrB_BOR_INT64, GrB_BAND_INT64, GrB_BXOR_INT64, GrB_BXNOR_INT64, + GrB_BOR_UINT8, GrB_BAND_UINT8, GrB_BXOR_UINT8, GrB_BXNOR_UINT8, + GrB_BOR_UINT16, GrB_BAND_UINT16, GrB_BXOR_UINT16, GrB_BXNOR_UINT16, + GrB_BOR_UINT32, GrB_BAND_UINT32, GrB_BXOR_UINT32, GrB_BXNOR_UINT32, + GrB_BOR_UINT64, GrB_BAND_UINT64, GrB_BXOR_UINT64, GrB_BXNOR_UINT64, + + // z = bitget(x,y) z = bitset(x,y) z = bitclr(x,y) + GxB_BGET_INT8, GxB_BSET_INT8, GxB_BCLR_INT8, + GxB_BGET_INT16, GxB_BSET_INT16, GxB_BCLR_INT16, + GxB_BGET_INT32, GxB_BSET_INT32, GxB_BCLR_INT32, + GxB_BGET_INT64, GxB_BSET_INT64, GxB_BCLR_INT64, + GxB_BGET_UINT8, GxB_BSET_UINT8, GxB_BCLR_UINT8, + GxB_BGET_UINT16, GxB_BSET_UINT16, GxB_BCLR_UINT16, + GxB_BGET_UINT32, GxB_BSET_UINT32, GxB_BCLR_UINT32, + GxB_BGET_UINT64, GxB_BSET_UINT64, GxB_BCLR_UINT64 ; + +//------------------------------------------------------------------------------ +// z=f(x,y) where z and x have the same type, but y is GrB_INT8 +//------------------------------------------------------------------------------ + + // z = bitshift (x,y) computes z = x left-shifted by y bits if y >= 0, or z + // = x right-shifted by (-y) bits if y < 0. z is equal to x if y is zero. + // z and x have the same type, as given by the suffix on the operator name. + // Since y must be signed, it cannot have the same type as x when x is + // unsigned; it is always GrB_INT8 for all 8 versions of this operator. + // The GxB_BSHIFT_* operators compute the arithmetic shift, and produce the + // same results as the MATLAB BITSHIFT function, for all possible inputs. + +GB_PUBLIC GrB_BinaryOp + + // z = bitshift(x,y) + GxB_BSHIFT_INT8, + GxB_BSHIFT_INT16, + GxB_BSHIFT_INT32, + GxB_BSHIFT_INT64, + GxB_BSHIFT_UINT8, + GxB_BSHIFT_UINT16, + GxB_BSHIFT_UINT32, + GxB_BSHIFT_UINT64 ; + +//------------------------------------------------------------------------------ +// z=f(x,y) where z is BOOL and the type of x,y is given by the suffix +//------------------------------------------------------------------------------ + +GB_PUBLIC GrB_BinaryOp + + // Six comparison operators z=f(x,y) return their result as boolean, but + // where x and y have the same type. The suffix in their names refers to + // the type of x and y since z is always boolean. If used as multiply + // operators in a semiring, they can only be combined with boolean monoids. + // The _BOOL versions of these operators give the same results as their + // IS*_BOOL counterparts. // z = (x == y) z = (x != y) z = (x > y) z = (x < y) GrB_EQ_BOOL, GrB_NE_BOOL, GrB_GT_BOOL, GrB_LT_BOOL, GrB_EQ_INT8, GrB_NE_INT8, GrB_GT_INT8, GrB_LT_INT8, - GrB_EQ_UINT8, GrB_NE_UINT8, GrB_GT_UINT8, GrB_LT_UINT8, GrB_EQ_INT16, GrB_NE_INT16, GrB_GT_INT16, GrB_LT_INT16, - GrB_EQ_UINT16, GrB_NE_UINT16, GrB_GT_UINT16, GrB_LT_UINT16, GrB_EQ_INT32, GrB_NE_INT32, GrB_GT_INT32, GrB_LT_INT32, - GrB_EQ_UINT32, GrB_NE_UINT32, GrB_GT_UINT32, GrB_LT_UINT32, GrB_EQ_INT64, GrB_NE_INT64, GrB_GT_INT64, GrB_LT_INT64, + GrB_EQ_UINT8, GrB_NE_UINT8, GrB_GT_UINT8, GrB_LT_UINT8, + GrB_EQ_UINT16, GrB_NE_UINT16, GrB_GT_UINT16, GrB_LT_UINT16, + GrB_EQ_UINT32, GrB_NE_UINT32, GrB_GT_UINT32, GrB_LT_UINT32, GrB_EQ_UINT64, GrB_NE_UINT64, GrB_GT_UINT64, GrB_LT_UINT64, GrB_EQ_FP32, GrB_NE_FP32, GrB_GT_FP32, GrB_LT_FP32, GrB_EQ_FP64, GrB_NE_FP64, GrB_GT_FP64, GrB_LT_FP64, + // complex: + GxB_EQ_FC32, GxB_NE_FC32, + GxB_EQ_FC64, GxB_NE_FC64, // z = (x >= y) z = (x <= y) GrB_GE_BOOL, GrB_LE_BOOL, GrB_GE_INT8, GrB_LE_INT8, - GrB_GE_UINT8, GrB_LE_UINT8, GrB_GE_INT16, GrB_LE_INT16, - GrB_GE_UINT16, GrB_LE_UINT16, GrB_GE_INT32, GrB_LE_INT32, - GrB_GE_UINT32, GrB_LE_UINT32, GrB_GE_INT64, GrB_LE_INT64, + GrB_GE_UINT8, GrB_LE_UINT8, + GrB_GE_UINT16, GrB_LE_UINT16, + GrB_GE_UINT32, GrB_LE_UINT32, GrB_GE_UINT64, GrB_LE_UINT64, GrB_GE_FP32, GrB_LE_FP32, - GrB_GE_FP64, GrB_LE_FP64, - -// Three binary operators operate on each of the types, converting them -// internally to boolean and returning a value 1 or 0 in the same type, for -// true or false. Each of them compute z = ((x != 0) OP (y != 0)), where x, y, -// and z all the same type. These operators are useful as multiply operators -// when combined with non-boolean monoids of the same type. + GrB_GE_FP64, GrB_LE_FP64 ; - // z = (x || y) z = (x && y) z = (x != y) - GxB_LOR_BOOL, GxB_LAND_BOOL, GxB_LXOR_BOOL, - GxB_LOR_INT8, GxB_LAND_INT8, GxB_LXOR_INT8, - GxB_LOR_UINT8, GxB_LAND_UINT8, GxB_LXOR_UINT8, - GxB_LOR_INT16, GxB_LAND_INT16, GxB_LXOR_INT16, - GxB_LOR_UINT16, GxB_LAND_UINT16, GxB_LXOR_UINT16, - GxB_LOR_INT32, GxB_LAND_INT32, GxB_LXOR_INT32, - GxB_LOR_UINT32, GxB_LAND_UINT32, GxB_LXOR_UINT32, - GxB_LOR_INT64, GxB_LAND_INT64, GxB_LXOR_INT64, - GxB_LOR_UINT64, GxB_LAND_UINT64, GxB_LXOR_UINT64, - GxB_LOR_FP32, GxB_LAND_FP32, GxB_LXOR_FP32, - GxB_LOR_FP64, GxB_LAND_FP64, GxB_LXOR_FP64, +//------------------------------------------------------------------------------ +// z=f(x,y) where z is complex and the type of x,y is given by the suffix +//------------------------------------------------------------------------------ -// Finally, three binary operate only on boolean types: LOR, LAND, LXOR. The -// naming convention differs (_BOOL is not appended to the name). They are -// the same as GxB_LOR_BOOL, GxB_LAND_BOOL, and GxB_LXOR_BOOL; they just -// have a simpler name. +GB_PUBLIC GrB_BinaryOp + // z = cmplx (x,y) + GxB_CMPLX_FP32, + GxB_CMPLX_FP64 ; - // z = (x || y) z = (x && y) z = (x != y) - GrB_LOR, GrB_LAND, GrB_LXOR ; +//------------------------------------------------------------------------------ +// About boolean and bitwise binary operators +//------------------------------------------------------------------------------ -// Some of the boolean operators compute the same thing but have unique names. +// Some of the boolean operators compute the same thing with different names. // For example, x*y and x&&y give the same results for boolean x and y. // Operations such as x < y when x and y are boolean are treated as if true=1 -// and false=0. Below is the truth table for all 17 binary operators with -// boolean inputs. This table is defined by how C typecasts boolean values for +// and false=0. Below is the truth table for all binary operators with boolean +// inputs. This table is defined by how C typecasts boolean values for // non-boolean operations. For example, if x, y, and z are boolean, x = true, // and y = true, then z = x + y = true + true = true. DIV (x/y) is defined // below. RDIV (y/x) is shown as \ in the table; it is the same as 2nd. -// is is is is is is -// x y 1st 2nd min max + - * / or and xor eq ne gt lt ge le rdiv -// 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 -// 0 1 0 1 0 1 1 1 0 0 1 0 1 0 1 0 1 0 1 1 -// 1 0 1 0 0 1 1 1 0 1 1 0 1 0 1 1 0 1 0 0 -// 1 1 1 1 1 1 1 0 1 1 1 1 0 1 0 0 0 1 1 1 +// x y 1st 2nd min max + - * / or and xor eq ne > < ge le \ pow pair +// 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 1 1 +// 0 1 0 1 0 1 1 1 0 0 1 0 1 0 1 0 1 0 1 1 0 1 +// 1 0 1 0 0 1 1 1 0 1 1 0 1 0 1 1 0 1 0 0 1 1 +// 1 1 1 1 1 1 1 0 1 1 1 1 0 1 0 0 0 1 1 1 1 1 // SPEC: the definition of divide-by-zero is an extension to the spec @@ -864,28 +1179,46 @@ GB_PUBLIC GrB_BinaryOp // (z = x). // With this convention for boolean "division", there are 11 unique binary -// operators that are purely boolean; 13 *_BOOL operators are redundant but are -// included in GraphBLAS so that the name space of operators is complete: - -// z = 1 PAIR -// z = x FIRST, DIV -// z = y SECOND, RDIV -// z = (x && y) AND, MIN, TIMES -// z = (x || y) OR, MAX, PLUS -// z = (x != y) XOR, MINUS, RMINUS, NE, ISNE -// z = (x == y) EQ, ISEQ -// z = (x > y) GT, ISGT -// z = (x < y) LT, ISLT -// z = (x >= y) GE, ISGE -// z = (x >= y) LE, ISLE - -// Three more that have no_BOOL suffix are also redundant with the operators -// of the form GxB_*_BOOL. -// (GrB_LOR, GrB_LAND, and GrB_LXOR). - -// There are thus 278 built-in binary operators with unique names, 18 of which -// are redundant, giving 260 built-in binary operators that compute unique -// results. +// operators that are purely boolean. Other named *_BOOL operators are +// redundant but are included in GraphBLAS so that the name space of operators +// is complete. Below is a list of all operators and their equivalents. + +// x: 0 0 1 1 +// y: 0 1 0 1 +// z: see below +// +// z = 0 0 0 0 0 (zero function, not predefined) +// z = (x && y) 0 0 0 1 AND, MIN, TIMES +// z = (x > y) 0 0 1 0 GT, ISGT, and set diff (x\y) +// z = x 0 0 1 1 FIRST, DIV +// +// z = (x < y) 0 1 0 0 LT, ISLT, and set diff (y\x) +// z = y 0 1 0 1 SECOND, RDIV +// z = (x != y) 0 1 1 0 XOR, MINUS, RMINUS, NE, ISNE +// z = (x || y) 0 1 1 1 OR, MAX, PLUS +// +// z = ~(x || y) 1 0 0 0 (nor(x,y) function, not predefined) +// z = (x == y) 1 0 0 1 LXNOR, EQ, ISEQ +// z = ~y 1 0 1 0 (not(y), not predefined) +// z = (x >= y) 1 0 1 1 GE, ISGE, POW, and "x implies y" +// +// z = ~x 1 1 0 0 (not(x), not predefined) +// z = (x >= y) 1 1 0 1 LE, ISLE, and "y implies x" +// z = ~(x && y) 1 1 1 0 (nand(x,y) function, not predefined) +// z = 1 1 1 1 1 PAIR +// +// z = any(x,y) . . . . ANY (pick x or y arbitrarily) + +// Four more that have no _BOOL suffix are also redundant with the operators +// of the form GxB_*_BOOL (GrB_LOR, GrB_LAND, GrB_LXOR, and GrB_LXNOR). + +// Note that the boolean binary operator space is not complete. Five other +// boolean functions could be pre-defined as well: z = 0, nor(x,y), +// nand(x,y), not(x), and not(y). + +// Four of the possible 16 bitwise operators are pre-defined: BOR, BAND, +// BXOR, and BXNOR. This assumes that the computations for each bit are +// entirely independent (so BSHIFT would not fit in the table above). //------------------------------------------------------------------------------ // methods for binary operators @@ -1047,7 +1380,7 @@ GB_PUBLIC GxB_SelectOp // all user-defined types. // GxB_GT_*, GxB_GE_*, GxB_LT_*, and GxB_LE_* only work on the 11 built-in -// types. They cannot be used for user-defined types. +// types (not complex). They cannot be used for user-defined types. //------------------------------------------------------------------------------ // select operators @@ -1214,6 +1547,22 @@ GrB_Info GrB_Monoid_new_FP64 // create a new double monoid double identity // identity value of the monoid ) ; +GB_PUBLIC +GrB_Info GxB_Monoid_new_FC32 // create a new float complex monoid +( + GrB_Monoid *monoid, // handle of monoid to create + GrB_BinaryOp op, // binary operator of the monoid + GxB_FC32_t identity // identity value of the monoid +) ; + +GB_PUBLIC +GrB_Info GxB_Monoid_new_FC64 // create a new double complex monoid +( + GrB_Monoid *monoid, // handle of monoid to create + GrB_BinaryOp op, // binary operator of the monoid + GxB_FC64_t identity // identity value of the monoid +) ; + GB_PUBLIC GrB_Info GrB_Monoid_new_UDT // create a monoid with a user-defined type ( @@ -1237,36 +1586,8 @@ GrB_Info GrB_Monoid_new // create a monoid */ #if GxB_STDC_VERSION >= 201112L -#define GrB_Monoid_new(monoid,op,identity) \ - _Generic \ - ( \ - (identity), \ - const bool : GrB_Monoid_new_BOOL , \ - bool : GrB_Monoid_new_BOOL , \ - const int8_t : GrB_Monoid_new_INT8 , \ - int8_t : GrB_Monoid_new_INT8 , \ - const uint8_t : GrB_Monoid_new_UINT8 , \ - uint8_t : GrB_Monoid_new_UINT8 , \ - const int16_t : GrB_Monoid_new_INT16 , \ - int16_t : GrB_Monoid_new_INT16 , \ - const uint16_t : GrB_Monoid_new_UINT16 , \ - uint16_t : GrB_Monoid_new_UINT16 , \ - const int32_t : GrB_Monoid_new_INT32 , \ - int32_t : GrB_Monoid_new_INT32 , \ - const uint32_t : GrB_Monoid_new_UINT32 , \ - uint32_t : GrB_Monoid_new_UINT32 , \ - const int64_t : GrB_Monoid_new_INT64 , \ - int64_t : GrB_Monoid_new_INT64 , \ - const uint64_t : GrB_Monoid_new_UINT64 , \ - uint64_t : GrB_Monoid_new_UINT64 , \ - const float : GrB_Monoid_new_FP32 , \ - float : GrB_Monoid_new_FP32 , \ - const double : GrB_Monoid_new_FP64 , \ - double : GrB_Monoid_new_FP64 , \ - const void * : GrB_Monoid_new_UDT , \ - void * : GrB_Monoid_new_UDT \ - ) \ - (monoid, op, identity) ; +#define GrB_Monoid_new(monoid,op,identity) \ + _Generic ((identity), GB_(, GrB, Monoid_new)) (monoid, op, identity) ; #endif // GxB_Monoid_terminal_new is identical to GrB_Monoid_new, except that a @@ -1373,6 +1694,24 @@ GrB_Info GxB_Monoid_terminal_new_FP64 // create a new double monoid double terminal // terminal value of the monoid ) ; +GB_PUBLIC +GrB_Info GxB_Monoid_terminal_new_FC32 // create a new float complex monoid +( + GrB_Monoid *monoid, // handle of monoid to create + GrB_BinaryOp op, // binary operator of the monoid + GxB_FC32_t identity, // identity value of the monoid + GxB_FC32_t terminal // terminal value of the monoid +) ; + +GB_PUBLIC +GrB_Info GxB_Monoid_terminal_new_FC64 // create a new double complex monoid +( + GrB_Monoid *monoid, // handle of monoid to create + GrB_BinaryOp op, // binary operator of the monoid + GxB_FC64_t identity, // identity value of the monoid + GxB_FC64_t terminal // terminal value of the monoid +) ; + GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_UDT // create a monoid with a user type ( @@ -1399,34 +1738,7 @@ GrB_Info GxB_Monoid_terminal_new // create a monoid #if GxB_STDC_VERSION >= 201112L #define GxB_Monoid_terminal_new(monoid,op,identity,terminal) \ - _Generic \ - ( \ - (identity), \ - const bool : GxB_Monoid_terminal_new_BOOL , \ - bool : GxB_Monoid_terminal_new_BOOL , \ - const int8_t : GxB_Monoid_terminal_new_INT8 , \ - int8_t : GxB_Monoid_terminal_new_INT8 , \ - const uint8_t : GxB_Monoid_terminal_new_UINT8 , \ - uint8_t : GxB_Monoid_terminal_new_UINT8 , \ - const int16_t : GxB_Monoid_terminal_new_INT16 , \ - int16_t : GxB_Monoid_terminal_new_INT16 , \ - const uint16_t : GxB_Monoid_terminal_new_UINT16 , \ - uint16_t : GxB_Monoid_terminal_new_UINT16 , \ - const int32_t : GxB_Monoid_terminal_new_INT32 , \ - int32_t : GxB_Monoid_terminal_new_INT32 , \ - const uint32_t : GxB_Monoid_terminal_new_UINT32 , \ - uint32_t : GxB_Monoid_terminal_new_UINT32 , \ - const int64_t : GxB_Monoid_terminal_new_INT64 , \ - int64_t : GxB_Monoid_terminal_new_INT64 , \ - const uint64_t : GxB_Monoid_terminal_new_UINT64 , \ - uint64_t : GxB_Monoid_terminal_new_UINT64 , \ - const float : GxB_Monoid_terminal_new_FP32 , \ - float : GxB_Monoid_terminal_new_FP32 , \ - const double : GxB_Monoid_terminal_new_FP64 , \ - double : GxB_Monoid_terminal_new_FP64 , \ - const void * : GxB_Monoid_terminal_new_UDT , \ - void * : GxB_Monoid_terminal_new_UDT \ - ) \ + _Generic ((identity), GB_(, GxB, Monoid_terminal_new)) \ (monoid, op, identity, terminal) ; #endif @@ -1527,9 +1839,7 @@ GrB_Info GrB_Semiring_free // free a user-created semiring // opaque to the user; their internal structure may change in future releases. typedef struct GB_Matrix_opaque *GrB_Matrix ; - typedef struct GB_Vector_opaque *GrB_Vector ; - typedef struct GB_Scalar_opaque *GxB_Scalar ; //============================================================================== @@ -1667,6 +1977,20 @@ GrB_Info GxB_Scalar_setElement_FP64 // s = x double x // user scalar to assign to s ) ; +GB_PUBLIC +GrB_Info GxB_Scalar_setElement_FC32 // s = x +( + GxB_Scalar s, // GxB_Scalar to modify + GxB_FC32_t x // user scalar to assign to s +) ; + +GB_PUBLIC +GrB_Info GxB_Scalar_setElement_FC64 // s = x +( + GxB_Scalar s, // GxB_Scalar to modify + GxB_FC64_t x // user scalar to assign to s +) ; + GB_PUBLIC GrB_Info GxB_Scalar_setElement_UDT // s = x ( @@ -1689,43 +2013,15 @@ GrB_Info GxB_Scalar_setElement // s = x */ #if GxB_STDC_VERSION >= 201112L -#define GxB_Scalar_setElement(s,x) \ - _Generic \ - ( \ - (x), \ - const bool : GxB_Scalar_setElement_BOOL , \ - bool : GxB_Scalar_setElement_BOOL , \ - const int8_t : GxB_Scalar_setElement_INT8 , \ - int8_t : GxB_Scalar_setElement_INT8 , \ - const uint8_t : GxB_Scalar_setElement_UINT8 , \ - uint8_t : GxB_Scalar_setElement_UINT8 , \ - const int16_t : GxB_Scalar_setElement_INT16 , \ - int16_t : GxB_Scalar_setElement_INT16 , \ - const uint16_t : GxB_Scalar_setElement_UINT16 , \ - uint16_t : GxB_Scalar_setElement_UINT16 , \ - const int32_t : GxB_Scalar_setElement_INT32 , \ - int32_t : GxB_Scalar_setElement_INT32 , \ - const uint32_t : GxB_Scalar_setElement_UINT32 , \ - uint32_t : GxB_Scalar_setElement_UINT32 , \ - const int64_t : GxB_Scalar_setElement_INT64 , \ - int64_t : GxB_Scalar_setElement_INT64 , \ - const uint64_t : GxB_Scalar_setElement_UINT64 , \ - uint64_t : GxB_Scalar_setElement_UINT64 , \ - const float : GxB_Scalar_setElement_FP32 , \ - float : GxB_Scalar_setElement_FP32 , \ - const double : GxB_Scalar_setElement_FP64 , \ - double : GxB_Scalar_setElement_FP64 , \ - const void * : GxB_Scalar_setElement_UDT , \ - void * : GxB_Scalar_setElement_UDT \ - ) \ - (s, x) +#define GxB_Scalar_setElement(s,x) \ + _Generic ((x), GB_(, GxB, Scalar_setElement)) (s, x) #endif //------------------------------------------------------------------------------ // GxB_Scalar_extractElement //------------------------------------------------------------------------------ -// Extract a single entry from a GxB_scalar, x = s, typecasting from the type +// Extract a single entry from a GxB_Scalar, x = s, typecasting from the type // of s to the type of x as needed. // Returns GrB_SUCCESS if s has an entry, and sets x to its value. @@ -1808,6 +2104,20 @@ GrB_Info GxB_Scalar_extractElement_FP64 // x = s const GxB_Scalar s // GxB_Scalar to extract an entry from ) ; +GB_PUBLIC +GrB_Info GxB_Scalar_extractElement_FC32 // x = s +( + GxB_FC32_t *x, // user scalar extracted + const GxB_Scalar s // GxB_Scalar to extract an entry from +) ; + +GB_PUBLIC +GrB_Info GxB_Scalar_extractElement_FC64 // x = s +( + GxB_FC64_t *x, // user scalar extracted + const GxB_Scalar s // GxB_Scalar to extract an entry from +) ; + GB_PUBLIC GrB_Info GxB_Scalar_extractElement_UDT // x = s ( @@ -1830,24 +2140,8 @@ GrB_Info GxB_Scalar_extractElement // x = s */ #if GxB_STDC_VERSION >= 201112L -#define GxB_Scalar_extractElement(x,s) \ - _Generic \ - ( \ - (x), \ - bool *: GxB_Scalar_extractElement_BOOL , \ - int8_t *: GxB_Scalar_extractElement_INT8 , \ - uint8_t *: GxB_Scalar_extractElement_UINT8 , \ - int16_t *: GxB_Scalar_extractElement_INT16 , \ - uint16_t *: GxB_Scalar_extractElement_UINT16 , \ - int32_t *: GxB_Scalar_extractElement_INT32 , \ - uint32_t *: GxB_Scalar_extractElement_UINT32 , \ - int64_t *: GxB_Scalar_extractElement_INT64 , \ - uint64_t *: GxB_Scalar_extractElement_UINT64 , \ - float *: GxB_Scalar_extractElement_FP32 , \ - double *: GxB_Scalar_extractElement_FP64 , \ - void *: GxB_Scalar_extractElement_UDT \ - ) \ - (x, s) +#define GxB_Scalar_extractElement(x,s) \ + _Generic ((x), GB_(*, GxB, Scalar_extractElement)) (x, s) #endif //============================================================================== @@ -1922,8 +2216,8 @@ GrB_Info GrB_Vector_free // free a vector // type of the dup operator, as needed (user-defined types cannot be cast). // Duplicates are assembled together with the dup operator. If two tuples // (i,x1) and (i,x2) have the same row index, then w(i) = dup (x1,x2). All -// three types of dup must be the same. The types of C, X, and dup must be -// compatible. +// three types of x,y,z of z=dup(x,y) must be the same. The types of C, X, and +// dup must be compatible. // SPEC: extension: well-defined behavior of a non-associative dup operator. @@ -2049,62 +2343,55 @@ GrB_Info GrB_Vector_build_FP64 // build a vector from (I,X) tuples ) ; GB_PUBLIC -GrB_Info GrB_Vector_build_UDT // build a vector from (I,X) tuples +GrB_Info GxB_Vector_build_FC32 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build const GrB_Index *I, // array of row indices of tuples - const void *X, // array of values of tuples + const GxB_FC32_t *X, // array of values of tuples GrB_Index nvals, // number of tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -// Type-generic version: X can be a pointer to any supported C type or void * -// for a user-defined type. - -/* - GB_PUBLIC -GrB_Info GrB_Vector_build // build a vector from (I,X) tuples +GrB_Info GxB_Vector_build_FC64 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build const GrB_Index *I, // array of row indices of tuples - const *X, // array of values of tuples + const GxB_FC64_t *X, // array of values of tuples GrB_Index nvals, // number of tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -*/ - +GB_PUBLIC +GrB_Info GrB_Vector_build_UDT // build a vector from (I,X) tuples +( + GrB_Vector w, // vector to build + const GrB_Index *I, // array of row indices of tuples + const void *X, // array of values of tuples + GrB_Index nvals, // number of tuples + const GrB_BinaryOp dup // binary function to assemble duplicates +) ; + +// Type-generic version: X can be a pointer to any supported C type or void * +// for a user-defined type. + +/* + +GB_PUBLIC +GrB_Info GrB_Vector_build // build a vector from (I,X) tuples +( + GrB_Vector w, // vector to build + const GrB_Index *I, // array of row indices of tuples + const *X, // array of values of tuples + GrB_Index nvals, // number of tuples + const GrB_BinaryOp dup // binary function to assemble duplicates +) ; + +*/ + #if GxB_STDC_VERSION >= 201112L -#define GrB_Vector_build(w,I,X,nvals,dup) \ - _Generic \ - ( \ - (X), \ - const bool *: GrB_Vector_build_BOOL , \ - bool *: GrB_Vector_build_BOOL , \ - const int8_t *: GrB_Vector_build_INT8 , \ - int8_t *: GrB_Vector_build_INT8 , \ - const uint8_t *: GrB_Vector_build_UINT8 , \ - uint8_t *: GrB_Vector_build_UINT8 , \ - const int16_t *: GrB_Vector_build_INT16 , \ - int16_t *: GrB_Vector_build_INT16 , \ - const uint16_t *: GrB_Vector_build_UINT16 , \ - uint16_t *: GrB_Vector_build_UINT16 , \ - const int32_t *: GrB_Vector_build_INT32 , \ - int32_t *: GrB_Vector_build_INT32 , \ - const uint32_t *: GrB_Vector_build_UINT32 , \ - uint32_t *: GrB_Vector_build_UINT32 , \ - const int64_t *: GrB_Vector_build_INT64 , \ - int64_t *: GrB_Vector_build_INT64 , \ - const uint64_t *: GrB_Vector_build_UINT64 , \ - uint64_t *: GrB_Vector_build_UINT64 , \ - const float *: GrB_Vector_build_FP32 , \ - float *: GrB_Vector_build_FP32 , \ - const double *: GrB_Vector_build_FP64 , \ - double *: GrB_Vector_build_FP64 , \ - const void *: GrB_Vector_build_UDT , \ - void *: GrB_Vector_build_UDT \ - ) \ +#define GrB_Vector_build(w,I,X,nvals,dup) \ + _Generic ((X), GB_(*, GrB, Vector_build)) \ (w, I, ((const void *) (X)), nvals, dup) #endif @@ -2203,6 +2490,22 @@ GrB_Info GrB_Vector_setElement_FP64 // w(i) = x GrB_Index i // row index ) ; +GB_PUBLIC +GrB_Info GxB_Vector_setElement_FC32 // w(i) = x +( + GrB_Vector w, // vector to modify + GxB_FC32_t x, // scalar to assign to w(i) + GrB_Index i // row index +) ; + +GB_PUBLIC +GrB_Info GxB_Vector_setElement_FC64 // w(i) = x +( + GrB_Vector w, // vector to modify + GxB_FC64_t x, // scalar to assign to w(i) + GrB_Index i // row index +) ; + GB_PUBLIC GrB_Info GrB_Vector_setElement_UDT // w(i) = x ( @@ -2227,36 +2530,8 @@ GrB_Info GrB_Vector_setElement // w(i) = x */ #if GxB_STDC_VERSION >= 201112L -#define GrB_Vector_setElement(w,x,i) \ - _Generic \ - ( \ - (x), \ - const bool : GrB_Vector_setElement_BOOL , \ - bool : GrB_Vector_setElement_BOOL , \ - const int8_t : GrB_Vector_setElement_INT8 , \ - int8_t : GrB_Vector_setElement_INT8 , \ - const uint8_t : GrB_Vector_setElement_UINT8 , \ - uint8_t : GrB_Vector_setElement_UINT8 , \ - const int16_t : GrB_Vector_setElement_INT16 , \ - int16_t : GrB_Vector_setElement_INT16 , \ - const uint16_t : GrB_Vector_setElement_UINT16 , \ - uint16_t : GrB_Vector_setElement_UINT16 , \ - const int32_t : GrB_Vector_setElement_INT32 , \ - int32_t : GrB_Vector_setElement_INT32 , \ - const uint32_t : GrB_Vector_setElement_UINT32 , \ - uint32_t : GrB_Vector_setElement_UINT32 , \ - const int64_t : GrB_Vector_setElement_INT64 , \ - int64_t : GrB_Vector_setElement_INT64 , \ - const uint64_t : GrB_Vector_setElement_UINT64 , \ - uint64_t : GrB_Vector_setElement_UINT64 , \ - const float : GrB_Vector_setElement_FP32 , \ - float : GrB_Vector_setElement_FP32 , \ - const double : GrB_Vector_setElement_FP64 , \ - double : GrB_Vector_setElement_FP64 , \ - const void * : GrB_Vector_setElement_UDT , \ - void * : GrB_Vector_setElement_UDT \ - ) \ - (w, x, i) +#define GrB_Vector_setElement(w,x,i) \ + _Generic ((x), GB_(, GrB, Vector_setElement)) (w, x, i) #endif //------------------------------------------------------------------------------ @@ -2357,6 +2632,22 @@ GrB_Info GrB_Vector_extractElement_FP64 // x = v(i) GrB_Index i // row index ) ; +GB_PUBLIC +GrB_Info GxB_Vector_extractElement_FC32 // x = v(i) +( + GxB_FC32_t *x, // scalar extracted + const GrB_Vector v, // vector to extract an entry from + GrB_Index i // row index +) ; + +GB_PUBLIC +GrB_Info GxB_Vector_extractElement_FC64 // x = v(i) +( + GxB_FC64_t *x, // scalar extracted + const GrB_Vector v, // vector to extract an entry from + GrB_Index i // row index +) ; + GB_PUBLIC GrB_Info GrB_Vector_extractElement_UDT // x = v(i) ( @@ -2381,26 +2672,23 @@ GrB_Info GrB_Vector_extractElement // x = v(i) */ #if GxB_STDC_VERSION >= 201112L -#define GrB_Vector_extractElement(x,v,i) \ - _Generic \ - ( \ - (x), \ - bool *: GrB_Vector_extractElement_BOOL , \ - int8_t *: GrB_Vector_extractElement_INT8 , \ - uint8_t *: GrB_Vector_extractElement_UINT8 , \ - int16_t *: GrB_Vector_extractElement_INT16 , \ - uint16_t *: GrB_Vector_extractElement_UINT16 , \ - int32_t *: GrB_Vector_extractElement_INT32 , \ - uint32_t *: GrB_Vector_extractElement_UINT32 , \ - int64_t *: GrB_Vector_extractElement_INT64 , \ - uint64_t *: GrB_Vector_extractElement_UINT64 , \ - float *: GrB_Vector_extractElement_FP32 , \ - double *: GrB_Vector_extractElement_FP64 , \ - void *: GrB_Vector_extractElement_UDT \ - ) \ - (x, v, i) +#define GrB_Vector_extractElement(x,v,i) \ + _Generic ((x), GB_(*, GrB, Vector_extractElement)) (x, v, i) #endif +//------------------------------------------------------------------------------ +// GrB_Vector_removeElement +//------------------------------------------------------------------------------ + +// GrB_Vector_removeElement (v,i) removes the element v(i) from the vector v. + +GB_PUBLIC +GrB_Info GrB_Vector_removeElement +( + GrB_Vector v, // vector to remove an element from + GrB_Index i // index +) ; + //------------------------------------------------------------------------------ // GrB_Vector_extractTuples //------------------------------------------------------------------------------ @@ -2515,6 +2803,24 @@ GrB_Info GrB_Vector_extractTuples_FP64 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; +GB_PUBLIC +GrB_Info GxB_Vector_extractTuples_FC32 // [I,~,X] = find (v) +( + GrB_Index *I, // array for returning row indices of tuples + GxB_FC32_t *X, // array for returning values of tuples + GrB_Index *nvals, // I, X size on input; # tuples on output + const GrB_Vector v // vector to extract tuples from +) ; + +GB_PUBLIC +GrB_Info GxB_Vector_extractTuples_FC64 // [I,~,X] = find (v) +( + GrB_Index *I, // array for returning row indices of tuples + GxB_FC64_t *X, // array for returning values of tuples + GrB_Index *nvals, // I, X size on input; # tuples on output + const GrB_Vector v // vector to extract tuples from +) ; + GB_PUBLIC GrB_Info GrB_Vector_extractTuples_UDT // [I,~,X] = find (v) ( @@ -2541,24 +2847,8 @@ GrB_Info GrB_Vector_extractTuples // [I,~,X] = find (v) */ #if GxB_STDC_VERSION >= 201112L -#define GrB_Vector_extractTuples(I,X,nvals,v) \ - _Generic \ - ( \ - (X), \ - bool *: GrB_Vector_extractTuples_BOOL , \ - int8_t *: GrB_Vector_extractTuples_INT8 , \ - uint8_t *: GrB_Vector_extractTuples_UINT8 , \ - int16_t *: GrB_Vector_extractTuples_INT16 , \ - uint16_t *: GrB_Vector_extractTuples_UINT16 , \ - int32_t *: GrB_Vector_extractTuples_INT32 , \ - uint32_t *: GrB_Vector_extractTuples_UINT32 , \ - int64_t *: GrB_Vector_extractTuples_INT64 , \ - uint64_t *: GrB_Vector_extractTuples_UINT64 , \ - float *: GrB_Vector_extractTuples_FP32 , \ - double *: GrB_Vector_extractTuples_FP64 , \ - void *: GrB_Vector_extractTuples_UDT \ - ) \ - (I, X, nvals, v) +#define GrB_Vector_extractTuples(I,X,nvals,v) \ + _Generic ((X), GB_(*, GrB, Vector_extractTuples)) (I, X, nvals, v) #endif //============================================================================== @@ -2641,8 +2931,8 @@ GrB_Info GrB_Matrix_free // free a matrix // appear in any order. Values are typecasted from X into the type of C, as // needed (user-defined types cannot be cast). Duplicates are assembled // together with the dup operator. If two tuples (i,j,x1) and (i,j,x2) have -// the same row index, then C(i,j) = dup(x1,x2). All three types of dup must -// be the same, and dup, C, and X must be compatible. +// the same row index, then C(i,j) = dup(x1,x2). All three types of x,y,z +// for z=dup(x,y) must be the same; and dup, C, and X must be compatible. // SPEC: extension: well-defined behavior of a non-associative dup operator. @@ -2772,6 +3062,28 @@ GrB_Info GrB_Matrix_build_FP64 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; +GB_PUBLIC +GrB_Info GxB_Matrix_build_FC32 // build a matrix from (I,J,X) tuples +( + GrB_Matrix C, // matrix to build + const GrB_Index *I, // array of row indices of tuples + const GrB_Index *J, // array of column indices of tuples + const GxB_FC32_t *X, // array of values of tuples + GrB_Index nvals, // number of tuples + const GrB_BinaryOp dup // binary function to assemble duplicates +) ; + +GB_PUBLIC +GrB_Info GxB_Matrix_build_FC64 // build a matrix from (I,J,X) tuples +( + GrB_Matrix C, // matrix to build + const GrB_Index *I, // array of row indices of tuples + const GrB_Index *J, // array of column indices of tuples + const GxB_FC64_t *X, // array of values of tuples + GrB_Index nvals, // number of tuples + const GrB_BinaryOp dup // binary function to assemble duplicates +) ; + GB_PUBLIC GrB_Info GrB_Matrix_build_UDT // build a matrix from (I,J,X) tuples ( @@ -2802,35 +3114,8 @@ GrB_Info GrB_Matrix_build // build a matrix from (I,J,X) tuples */ #if GxB_STDC_VERSION >= 201112L -#define GrB_Matrix_build(C,I,J,X,nvals,dup) \ - _Generic \ - ( \ - (X), \ - const bool *: GrB_Matrix_build_BOOL , \ - bool *: GrB_Matrix_build_BOOL , \ - const int8_t *: GrB_Matrix_build_INT8 , \ - int8_t *: GrB_Matrix_build_INT8 , \ - const uint8_t *: GrB_Matrix_build_UINT8 , \ - uint8_t *: GrB_Matrix_build_UINT8 , \ - const int16_t *: GrB_Matrix_build_INT16 , \ - int16_t *: GrB_Matrix_build_INT16 , \ - const uint16_t *: GrB_Matrix_build_UINT16 , \ - uint16_t *: GrB_Matrix_build_UINT16 , \ - const int32_t *: GrB_Matrix_build_INT32 , \ - int32_t *: GrB_Matrix_build_INT32 , \ - const uint32_t *: GrB_Matrix_build_UINT32 , \ - uint32_t *: GrB_Matrix_build_UINT32 , \ - const int64_t *: GrB_Matrix_build_INT64 , \ - int64_t *: GrB_Matrix_build_INT64 , \ - const uint64_t *: GrB_Matrix_build_UINT64 , \ - uint64_t *: GrB_Matrix_build_UINT64 , \ - const float *: GrB_Matrix_build_FP32 , \ - float *: GrB_Matrix_build_FP32 , \ - const double *: GrB_Matrix_build_FP64 , \ - double *: GrB_Matrix_build_FP64 , \ - const void *: GrB_Matrix_build_UDT , \ - void *: GrB_Matrix_build_UDT \ - ) \ +#define GrB_Matrix_build(C,I,J,X,nvals,dup) \ + _Generic ((X), GB_(*, GrB, Matrix_build)) \ (C, I, J, ((const void *) (X)), nvals, dup) #endif @@ -2940,6 +3225,24 @@ GrB_Info GrB_Matrix_setElement_FP64 // C (i,j) = x GrB_Index j // column index ) ; +GB_PUBLIC +GrB_Info GxB_Matrix_setElement_FC32 // C (i,j) = x +( + GrB_Matrix C, // matrix to modify + GxB_FC32_t x, // scalar to assign to C(i,j) + GrB_Index i, // row index + GrB_Index j // column index +) ; + +GB_PUBLIC +GrB_Info GxB_Matrix_setElement_FC64 // C (i,j) = x +( + GrB_Matrix C, // matrix to modify + GxB_FC64_t x, // scalar to assign to C(i,j) + GrB_Index i, // row index + GrB_Index j // column index +) ; + GB_PUBLIC GrB_Info GrB_Matrix_setElement_UDT // C (i,j) = x ( @@ -2966,36 +3269,8 @@ GrB_Info GrB_Matrix_setElement // C (i,j) = x */ #if GxB_STDC_VERSION >= 201112L -#define GrB_Matrix_setElement(C,x,i,j) \ - _Generic \ - ( \ - (x), \ - const bool : GrB_Matrix_setElement_BOOL , \ - bool : GrB_Matrix_setElement_BOOL , \ - const int8_t : GrB_Matrix_setElement_INT8 , \ - int8_t : GrB_Matrix_setElement_INT8 , \ - const uint8_t : GrB_Matrix_setElement_UINT8 , \ - uint8_t : GrB_Matrix_setElement_UINT8 , \ - const int16_t : GrB_Matrix_setElement_INT16 , \ - int16_t : GrB_Matrix_setElement_INT16 , \ - const uint16_t : GrB_Matrix_setElement_UINT16 , \ - uint16_t : GrB_Matrix_setElement_UINT16 , \ - const int32_t : GrB_Matrix_setElement_INT32 , \ - int32_t : GrB_Matrix_setElement_INT32 , \ - const uint32_t : GrB_Matrix_setElement_UINT32 , \ - uint32_t : GrB_Matrix_setElement_UINT32 , \ - const int64_t : GrB_Matrix_setElement_INT64 , \ - int64_t : GrB_Matrix_setElement_INT64 , \ - const uint64_t : GrB_Matrix_setElement_UINT64 , \ - uint64_t : GrB_Matrix_setElement_UINT64 , \ - const float : GrB_Matrix_setElement_FP32 , \ - float : GrB_Matrix_setElement_FP32 , \ - const double : GrB_Matrix_setElement_FP64 , \ - double : GrB_Matrix_setElement_FP64 , \ - const void * : GrB_Matrix_setElement_UDT , \ - void * : GrB_Matrix_setElement_UDT \ - ) \ - (C, x, i, j) +#define GrB_Matrix_setElement(C,x,i,j) \ + _Generic ((x), GB_(, GrB, Matrix_setElement)) (C, x, i, j) #endif //------------------------------------------------------------------------------ @@ -3107,6 +3382,24 @@ GrB_Info GrB_Matrix_extractElement_FP64 // x = A(i,j) GrB_Index j // column index ) ; +GB_PUBLIC +GrB_Info GxB_Matrix_extractElement_FC32 // x = A(i,j) +( + GxB_FC32_t *x, // extracted scalar + const GrB_Matrix A, // matrix to extract a scalar from + GrB_Index i, // row index + GrB_Index j // column index +) ; + +GB_PUBLIC +GrB_Info GxB_Matrix_extractElement_FC64 // x = A(i,j) +( + GxB_FC64_t *x, // extracted scalar + const GrB_Matrix A, // matrix to extract a scalar from + GrB_Index i, // row index + GrB_Index j // column index +) ; + GB_PUBLIC GrB_Info GrB_Matrix_extractElement_UDT // x = A(i,j) ( @@ -3133,26 +3426,24 @@ GrB_Info GrB_Matrix_extractElement // x = A(i,j) */ #if GxB_STDC_VERSION >= 201112L -#define GrB_Matrix_extractElement(x,A,i,j) \ - _Generic \ - ( \ - (x), \ - bool *: GrB_Matrix_extractElement_BOOL , \ - int8_t *: GrB_Matrix_extractElement_INT8 , \ - uint8_t *: GrB_Matrix_extractElement_UINT8 , \ - int16_t *: GrB_Matrix_extractElement_INT16 , \ - uint16_t *: GrB_Matrix_extractElement_UINT16 , \ - int32_t *: GrB_Matrix_extractElement_INT32 , \ - uint32_t *: GrB_Matrix_extractElement_UINT32 , \ - int64_t *: GrB_Matrix_extractElement_INT64 , \ - uint64_t *: GrB_Matrix_extractElement_UINT64 , \ - float *: GrB_Matrix_extractElement_FP32 , \ - double *: GrB_Matrix_extractElement_FP64 , \ - void *: GrB_Matrix_extractElement_UDT \ - ) \ - (x, A, i, j) +#define GrB_Matrix_extractElement(x,A,i,j) \ + _Generic ((x), GB_(*, GrB, Matrix_extractElement)) (x, A, i, j) #endif +//------------------------------------------------------------------------------ +// GrB_Matrix_removeElement +//------------------------------------------------------------------------------ + +// GrB_Matrix_removeElement (A,i,j) removes the entry A(i,j) from the matrix A. + +GB_PUBLIC +GrB_Info GrB_Matrix_removeElement +( + GrB_Matrix C, // matrix to remove entry from + GrB_Index i, // row index + GrB_Index j // column index +) ; + //------------------------------------------------------------------------------ // GrB_Matrix_extractTuples //------------------------------------------------------------------------------ @@ -3278,6 +3569,26 @@ GrB_Info GrB_Matrix_extractTuples_FP64 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; +GB_PUBLIC +GrB_Info GxB_Matrix_extractTuples_FC32 // [I,J,X] = find (A) +( + GrB_Index *I, // array for returning row indices of tuples + GrB_Index *J, // array for returning col indices of tuples + GxB_FC32_t *X, // array for returning values of tuples + GrB_Index *nvals, // I,J,X size on input; # tuples on output + const GrB_Matrix A // matrix to extract tuples from +) ; + +GB_PUBLIC +GrB_Info GxB_Matrix_extractTuples_FC64 // [I,J,X] = find (A) +( + GrB_Index *I, // array for returning row indices of tuples + GrB_Index *J, // array for returning col indices of tuples + GxB_FC64_t *X, // array for returning values of tuples + GrB_Index *nvals, // I,J,X size on input; # tuples on output + const GrB_Matrix A // matrix to extract tuples from +) ; + GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_UDT // [I,J,X] = find (A) ( @@ -3306,24 +3617,8 @@ GrB_Info GrB_Matrix_extractTuples // [I,J,X] = find (A) */ #if GxB_STDC_VERSION >= 201112L -#define GrB_Matrix_extractTuples(I,J,X,nvals,A) \ - _Generic \ - ( \ - (X), \ - bool *: GrB_Matrix_extractTuples_BOOL , \ - int8_t *: GrB_Matrix_extractTuples_INT8 , \ - uint8_t *: GrB_Matrix_extractTuples_UINT8 , \ - int16_t *: GrB_Matrix_extractTuples_INT16 , \ - uint16_t *: GrB_Matrix_extractTuples_UINT16 , \ - int32_t *: GrB_Matrix_extractTuples_INT32 , \ - uint32_t *: GrB_Matrix_extractTuples_UINT32 , \ - int64_t *: GrB_Matrix_extractTuples_INT64 , \ - uint64_t *: GrB_Matrix_extractTuples_UINT64 , \ - float *: GrB_Matrix_extractTuples_FP32 , \ - double *: GrB_Matrix_extractTuples_FP64 , \ - void *: GrB_Matrix_extractTuples_UDT \ - ) \ - (I, J, X, nvals, A) +#define GrB_Matrix_extractTuples(I,J,X,nvals,A) \ + _Generic ((X), GB_(*, GrB, Matrix_extractTuples)) (I, J, X, nvals, A) #endif //============================================================================== @@ -3402,13 +3697,45 @@ GrB_Info GrB_Matrix_extractTuples // [I,J,X] = find (A) // large and the mask is not present, since it takes Omega(m*n) time // if C is m-by-n. -// GxB_NTHREADS and GxB_CHUNK are an enumerated value in both the -// GrB_Desc_Field and the GxB_Option_Field. They are defined with the same -// integer value for both enums, so the user can use them for both. - +// The following are enumerated values in both the GrB_Desc_Field and the +// GxB_Option_Field. They are defined with the same integer value for both +// enums, so the user can use them for both. #define GxB_NTHREADS 5 #define GxB_CHUNK 7 +// GxB_MKL (DRAFT: in progress, do not use) a boolean that controls the usage +// of the Intel MKL. If true, then MKL may be used; if false, MKL is not +// called. +#define GxB_MKL 31 + +// CUDA support (DRAFT: in progress, do not use) +// SuiteSparse:GraphBLAS can exploit a CUDA-aware GPU. CUDA must be avaiable +// when GraphBLAS is compiled (see the installations instructions), and it +// must also be requested at run time by called GxB_cuda_init instead of +// GrB_init or GxB_init. +// +// GxB_GPU_CONTROL: determines where the computation is performed. +// +// GxB_DEFAULT: decide based on where the matrix is, etc. +// GxB_GPU_ALWAYS: always use the GPU +// GxB_GPU_NEVER: never use the GPU +// type: GrB_Desc_Value (an enum) +// +// GxB_GPU_CHUNK: used by the GxB_GPU_AUTO rule, to decide when a +// problem is large enough to use the GPU. A double value. +// +// GxB_GPU_SET: an array of GPUs to use, defined by integers 0 to +// # of GPUs available - 1. For example: [2 4 6], if there are +// 8 GPUs. (FUTURE) +// +// GxB_cuda_init is not used, or if CUDA is not available when GraphBLAS is +// compiled as a library, then no GPUs are used and these settings are silently +// ignored. + +#define GxB_GPU_CONTROL 21 +#define GxB_GPU_CHUNK 22 +// #define GxB_GPU_SET 23 // FUTURE + // GxB_NTHREADS_MAX is no longer used, as of v3.2.0. #ifndef GxB_NTHREADS_MAX #define GxB_NTHREADS_MAX INT32_MAX @@ -3428,16 +3755,24 @@ typedef enum GxB_DESCRIPTOR_CHUNK = GxB_CHUNK, // chunk size for small problems. // If <= GxB_DEFAULT, then the default is used. + // GPU control (DRAFT: in progress, do not use) + GxB_DESCRIPTOR_GPU_CONTROL = GxB_GPU_CONTROL, + GxB_DESCRIPTOR_GPU_CHUNK = GxB_GPU_CHUNK, + // GxB_DESCRIPTOR_GPU_SET = GxB_GPU_SET, // FUTURE + + // MKL control (DRAFT: in progress, do not use) + GxB_DESCRIPTOR_MKL = GxB_MKL, // control usage of Intel MKL + // SuiteSparse:GraphBLAS extensions are given large values so they do not // conflict with future enum values added to the spec: GxB_AxB_METHOD = 1000 // descriptor for selecting C=A*B algorithm } GrB_Desc_Field ; -// SPEC: GxB_DEFAULT, GxB_NTHREADS, GxB_CHUNK and GxB_AxB_* are extensions to -// the spec. In the spec, setting both GrB_COMP and GrB_STRUCTURE can be done -// with two calls to GrB_Descriptor_set. As an extension to the spec, they can -// also be set with a single call, using the setting GrB_COMP+GrB_STRUCTURE. +// SPEC: GxB_DEFAULT, GxB_NTHREADS, GxB_CHUNK, and GxB_AxB_* are extensions. +// In the spec, setting both GrB_COMP and GrB_STRUCTURE can be done with two +// calls to GrB_Descriptor_set. As an extension to the spec, they can also be +// set with a single call, using the setting GrB_COMP+GrB_STRUCTURE. typedef enum { @@ -3455,6 +3790,10 @@ typedef enum // for GrB_INP0 and GrB_INP1 only: GrB_TRAN = 3, // use the transpose of the input + // for GxB_GPU_CONTROL only: + GxB_GPU_ALWAYS = 2001, + GxB_GPU_NEVER = 2002, + // for GxB_AxB_METHOD only: GxB_AxB_GUSTAVSON = 1001, // gather-scatter saxpy method GxB_AxB_HEAP = 1002, // heap-based saxpy method @@ -3543,42 +3882,42 @@ GrB_Descriptor // OUTP MASK MASK INP0 INP1 // GrB_NULL // - - - - - GrB_DESC_T1 , // - - - - GrB_TRAN -GrB_DESC_T0 , // - - - GrB_TRAN - +GrB_DESC_T0 , // - - - GrB_TRAN - GrB_DESC_T0T1 , // - - - GrB_TRAN GrB_TRAN -GrB_DESC_C , // - - GrB_COMP - - +GrB_DESC_C , // - - GrB_COMP - - GrB_DESC_CT1 , // - - GrB_COMP - GrB_TRAN -GrB_DESC_CT0 , // - - GrB_COMP GrB_TRAN - +GrB_DESC_CT0 , // - - GrB_COMP GrB_TRAN - GrB_DESC_CT0T1 , // - - GrB_COMP GrB_TRAN GrB_TRAN -GrB_DESC_S , // - GrB_STRUCTURE - - - +GrB_DESC_S , // - GrB_STRUCTURE - - - GrB_DESC_ST1 , // - GrB_STRUCTURE - - GrB_TRAN -GrB_DESC_ST0 , // - GrB_STRUCTURE - GrB_TRAN - +GrB_DESC_ST0 , // - GrB_STRUCTURE - GrB_TRAN - GrB_DESC_ST0T1 , // - GrB_STRUCTURE - GrB_TRAN GrB_TRAN -GrB_DESC_SC , // - GrB_STRUCTURE GrB_COMP - - +GrB_DESC_SC , // - GrB_STRUCTURE GrB_COMP - - GrB_DESC_SCT1 , // - GrB_STRUCTURE GrB_COMP - GrB_TRAN -GrB_DESC_SCT0 , // - GrB_STRUCTURE GrB_COMP GrB_TRAN - +GrB_DESC_SCT0 , // - GrB_STRUCTURE GrB_COMP GrB_TRAN - GrB_DESC_SCT0T1 , // - GrB_STRUCTURE GrB_COMP GrB_TRAN GrB_TRAN -GrB_DESC_R , // GrB_REPLACE - - - - +GrB_DESC_R , // GrB_REPLACE - - - - GrB_DESC_RT1 , // GrB_REPLACE - - - GrB_TRAN -GrB_DESC_RT0 , // GrB_REPLACE - - GrB_TRAN - +GrB_DESC_RT0 , // GrB_REPLACE - - GrB_TRAN - GrB_DESC_RT0T1 , // GrB_REPLACE - - GrB_TRAN GrB_TRAN -GrB_DESC_RC , // GrB_REPLACE - GrB_COMP - - +GrB_DESC_RC , // GrB_REPLACE - GrB_COMP - - GrB_DESC_RCT1 , // GrB_REPLACE - GrB_COMP - GrB_TRAN -GrB_DESC_RCT0 , // GrB_REPLACE - GrB_COMP GrB_TRAN - +GrB_DESC_RCT0 , // GrB_REPLACE - GrB_COMP GrB_TRAN - GrB_DESC_RCT0T1 , // GrB_REPLACE - GrB_COMP GrB_TRAN GrB_TRAN -GrB_DESC_RS , // GrB_REPLACE GrB_STRUCTURE - - - +GrB_DESC_RS , // GrB_REPLACE GrB_STRUCTURE - - - GrB_DESC_RST1 , // GrB_REPLACE GrB_STRUCTURE - - GrB_TRAN -GrB_DESC_RST0 , // GrB_REPLACE GrB_STRUCTURE - GrB_TRAN - +GrB_DESC_RST0 , // GrB_REPLACE GrB_STRUCTURE - GrB_TRAN - GrB_DESC_RST0T1 , // GrB_REPLACE GrB_STRUCTURE - GrB_TRAN GrB_TRAN -GrB_DESC_RSC , // GrB_REPLACE GrB_STRUCTURE GrB_COMP - - +GrB_DESC_RSC , // GrB_REPLACE GrB_STRUCTURE GrB_COMP - - GrB_DESC_RSCT1 , // GrB_REPLACE GrB_STRUCTURE GrB_COMP - GrB_TRAN -GrB_DESC_RSCT0 , // GrB_REPLACE GrB_STRUCTURE GrB_COMP GrB_TRAN - +GrB_DESC_RSCT0 , // GrB_REPLACE GrB_STRUCTURE GrB_COMP GrB_TRAN - GrB_DESC_RSCT0T1 ; // GrB_REPLACE GrB_STRUCTURE GrB_COMP GrB_TRAN GrB_TRAN // GrB_NULL is the default descriptor, with all settings at their defaults: @@ -3617,6 +3956,7 @@ GrB_DESC_RSCT0T1 ; // GrB_REPLACE GrB_STRUCTURE GrB_COMP GrB_TRAN GrB_TRAN // GxB_get: queries a global option, a GrB_Matrix option or a GrB_Descriptor // ADDED in V3.0: GxB_CHUNK, GxB_LIBRARY_*, GxB_API_* options: +// ADDED in V3.3: GxB_MKL and GxB_GPU* (DRAFT: in progress, do not use) typedef enum // for global options or matrix options { @@ -3628,9 +3968,7 @@ typedef enum // for global options or matrix options GxB_MODE = 2, // mode passed to GrB_init (blocking or non-blocking) GxB_THREAD_SAFETY = 3, // thread library that allows GraphBLAS to - // be thread-safe for user threads: this provides a - // critical section for user threads for GrB_wait - // and thread-local storage for GrB_error. + // be thread-safe for user threads. GxB_THREADING = 4, // thread library used for internal GraphBLAS threads @@ -3658,7 +3996,17 @@ typedef enum // for global options or matrix options GxB_API_DATE = 17, // date of the API (char *) GxB_API_ABOUT = 18, // about the API (char *) GxB_API_URL = 19, // URL for the API (char *) - GxB_BURBLE = 20 // development only (bool *) + + // GPU control (DRAFT: in progress, do not use) + GxB_GPU_COUNT = 20, // # of GPUs (query only) + GxB_GLOBAL_GPU_CONTROL = GxB_GPU_CONTROL, + GxB_GLOBAL_GPU_CHUNK = GxB_GPU_CHUNK, + // GxB_GLOBAL_GPU_SET = GxB_GPU_SET, // FUTURE + + // MKL control (DRAFT: in progress, do not use) + GxB_GLOBAL_MKL = GxB_MKL, // control usage of Intel MKL + + GxB_BURBLE = 99 // development only (bool *) } GxB_Option_Field ; @@ -3731,11 +4079,13 @@ GrB_Info GxB_Matrix_Option_get // gets the current option of a matrix // GxB_Global_Option_set (GxB_HYPER, GxB_HYPER_DEFAULT) ; // GxB_Global_Option_set (GxB_FORMAT, GxB_FORMAT_DEFAULT) ; // -// That is, by default, all new matrices are held by column in CSC format. If -// a matrix has fewer than n/16 columns, it can be converted to hypersparse -// format. If it has more than n/8 columns, it can be converted to -// non-hypersparse format. GxB_Global_Option_set has no effect on matrices -// already created. +// The compile-time constants GxB_HYPER_DEFAULT and GxB_FORMAT_DEFAULT are +// equal to 0.625 and GxB_BY_ROW, by default. That is, by default, all new +// matrices are held by row in CSR format. If a matrix has fewer than n/16 +// columns, it can be converted to hypersparse format. If it has more than n/8 +// columns, it can be converted to non-hypersparse format. Modifying these +// global settings via GxB_Global_Option_set has no effect on matrices already +// created. GB_PUBLIC GrB_Info GxB_Global_Option_set // set a global default option @@ -3776,6 +4126,26 @@ GrB_Info GxB_Global_Option_get // gets the current global default option // // GxB_set (GxB_CHUNK, double chunk) ; // GxB_get (GxB_CHUNK, double *chunk) ; +// +// GxB_set (GxB_BURBLE, bool burble) ; +// GxB_get (GxB_BURBLE, bool *burble) ; + +// To set/get the global GPU options: (DRAFT: in progress, do not use) +// +// GxB_set (GxB_GPU_CONTROL, GxB_DEFAULT) ; +// GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; +// GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; +// GxB_get (GxB_GPU_CONTROL, GrB_Desc_Value *) +// +// GxB_set (GxB_GPU_CHUNK, double chunk) ; +// GxB_get (GxB_GPU_CHUNK, double *chunk) ; +// +// GxB_get (GxB_GPU_COUNT, int *ngpus) ; // query only + +// To set/get the global MKL options: (DRAFT: in progress, do not use) +// +// GxB_set (GxB_MKL, bool use_mkl) ; +// GxB_get (GxB_MKL, bool *use_mkl) ; // To get global options that can be queried but not modified: // @@ -3794,6 +4164,16 @@ GrB_Info GxB_Global_Option_get // gets the current global default option // GxB_set (GrB_Matrix A, GxB_FORMAT, GxB_BY_COL) ; // GxB_get (GrB_Matrix A, GxB_FORMAT, GxB_Format_Value *s) ; +// To set/get the matrix GPU options: (DRAFT: in progress, do not use) +// +// GxB_set (GrB_Matrix A, GxB_GPU_CONTROL, GxB_DEFAULT) ; +// GxB_set (GrB_Matrix A, GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; +// GxB_set (GrB_Matrix A, GxB_GPU_CONTROL, GxB_GPU_NEVER) ; +// GxB_get (GrB_Matrix A, GxB_GPU_CONTROL, GrB_Desc_Value *) +// +// GxB_set (GrB_Matrix A, GxB_GPU_CHUNK, double chunk) ; +// GxB_get (GrB_Matrix A, GxB_GPU_CHUNK, double *chunk) ; + // To get a matrix status (modified with GxB_HYPER, double h parameter): // // GxB_get (GrB_Matrix A, GxB_IS_HYPER, bool *is_hyper) ; @@ -3807,6 +4187,7 @@ GrB_Info GxB_Global_Option_get // gets the current global default option // GxB_set (GrB_Descriptor d, GrB_MASK, GxB_DEFAULT) ; // GxB_set (GrB_Descriptor d, GrB_MASK, GrB_COMP) ; // GxB_set (GrB_Descriptor d, GrB_MASK, GrB_STRUCTURE) ; +// GxB_set (GrB_Descriptor d, GrB_MASK, GrB_COMP + GrB_STRUCTURE) ; // GxB_get (GrB_Descriptor d, GrB_MASK, GrB_Desc_Value *v) ; // // GxB_set (GrB_Descriptor d, GrB_INP0, GxB_DEFAULT) ; @@ -3831,6 +4212,21 @@ GrB_Info GxB_Global_Option_get // gets the current global default option // GxB_set (GrB_Descriptor d, GxB_CHUNK, double chunk) ; // GxB_get (GrB_Descriptor d, GxB_CHUNK, double *chunk) ; +// To set/get the descriptor MKL options: (DRAFT: in progress, do not use) +// +// GxB_set (GrB_Descriptor d, GxB_MKL, bool use_mkl) ; +// GxB_get (GrB_Descriptor d, GxB_MKL, bool *use_mkl) ; + +// To set/get the descriptor GPU options: (DRAFT: in progress, do not use) +// +// GxB_set (GrB_Descriptor d, GxB_GPU_CONTROL, GxB_DEFAULT) ; +// GxB_set (GrB_Descriptor d, GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; +// GxB_set (GrB_Descriptor d, GxB_GPU_CONTROL, GxB_GPU_NEVER) ; +// GxB_get (GrB_Descriptor d, GxB_GPU_CONTROL, GrB_Desc_Value *) +// +// GxB_set (GrB_Descriptor d, GxB_GPU_CHUNK, double chunk) ; +// GxB_get (GrB_Descriptor d, GxB_GPU_CHUNK, double *chunk) ; + #if GxB_STDC_VERSION >= 201112L #define GxB_set(arg1,...) \ _Generic \ @@ -3859,7 +4255,6 @@ GrB_Info GxB_Global_Option_get // gets the current global default option (arg1, __VA_ARGS__) #endif - //============================================================================== //=== GrB_free ================================================================= //============================================================================== @@ -3891,6 +4286,51 @@ GrB_Info GxB_Global_Option_get // gets the current global default option (object) #endif +//============================================================================== +//=== GraphBLAS sequence termination =========================================== +//============================================================================== + +// Finish all pending work in a specific object. + +GB_PUBLIC GrB_Info GrB_Type_wait (GrB_Type *type ) ; +GB_PUBLIC GrB_Info GrB_UnaryOp_wait (GrB_UnaryOp *op ) ; +GB_PUBLIC GrB_Info GrB_BinaryOp_wait (GrB_BinaryOp *op ) ; +GB_PUBLIC GrB_Info GxB_SelectOp_wait (GxB_SelectOp *op ) ; +GB_PUBLIC GrB_Info GrB_Monoid_wait (GrB_Monoid *monoid ) ; +GB_PUBLIC GrB_Info GrB_Semiring_wait (GrB_Semiring *semiring) ; +GB_PUBLIC GrB_Info GrB_Descriptor_wait (GrB_Descriptor *desc ) ; +GB_PUBLIC GrB_Info GxB_Scalar_wait (GxB_Scalar *s ) ; +GB_PUBLIC GrB_Info GrB_Vector_wait (GrB_Vector *v ) ; +GB_PUBLIC GrB_Info GrB_Matrix_wait (GrB_Matrix *A ) ; + +// TODO in 4.0: GrB_wait (with no inputs) is deprecated, and also not +// compatible with the polymorphic GrB_wait (&object). In V4.0, +// GrB_wait ( ) will be removed, and the polymorphic GrB_wait (&object) +// will be added. + +GB_PUBLIC GrB_Info GrB_wait (void) ; // DEPRECATED: TODO in 4.0: delete + +// TODO in 4.0: add GrB_wait (&object) polymorphic function: +/* +#define GrB_wait(object) \ + _Generic \ + ( \ + (object), \ + GrB_Type *: GrB_Type_wait , \ + GrB_UnaryOp *: GrB_UnaryOp_wait , \ + GrB_BinaryOp *: GrB_BinaryOp_wait , \ + GxB_SelectOp *: GxB_SelectOp_wait , \ + GrB_Monoid *: GrB_Monoid_wait , \ + GrB_Semiring *: GrB_Semiring_wait , \ + GxB_Scalar *: GxB_Scalar_wait , \ + GrB_Vector *: GrB_Vector_wait , \ + GrB_Matrix *: GrB_Matrix_wait , \ + GrB_Descriptor *: GrB_Descriptor_wait \ + ) \ + (object) +#endif +*/ + //============================================================================== //=== GraphBLAS operations ===================================================== //============================================================================== @@ -3985,7 +4425,7 @@ GrB_Info GrB_mxv // w = accum (w, A*u) // operator instead. For a monoid, the mult operator is the monoid operator. GB_PUBLIC -GrB_Info GrB_eWiseMult_Vector_Semiring // w = accum (w, u.*v) +GrB_Info GrB_Vector_eWiseMult_Semiring // w = accum (w, u.*v) ( GrB_Vector w, // input/output vector for results const GrB_Vector mask, // optional mask for w, unused if NULL @@ -3997,7 +4437,7 @@ GrB_Info GrB_eWiseMult_Vector_Semiring // w = accum (w, u.*v) ) ; GB_PUBLIC -GrB_Info GrB_eWiseMult_Vector_Monoid // w = accum (w, u.*v) +GrB_Info GrB_Vector_eWiseMult_Monoid // w = accum (w, u.*v) ( GrB_Vector w, // input/output vector for results const GrB_Vector mask, // optional mask for w, unused if NULL @@ -4009,7 +4449,7 @@ GrB_Info GrB_eWiseMult_Vector_Monoid // w = accum (w, u.*v) ) ; GB_PUBLIC -GrB_Info GrB_eWiseMult_Vector_BinaryOp // w = accum (w, u.*v) +GrB_Info GrB_Vector_eWiseMult_BinaryOp // w = accum (w, u.*v) ( GrB_Vector w, // input/output vector for results const GrB_Vector mask, // optional mask for w, unused if NULL @@ -4021,7 +4461,7 @@ GrB_Info GrB_eWiseMult_Vector_BinaryOp // w = accum (w, u.*v) ) ; GB_PUBLIC -GrB_Info GrB_eWiseMult_Matrix_Semiring // C = accum (C, A.*B) +GrB_Info GrB_Matrix_eWiseMult_Semiring // C = accum (C, A.*B) ( GrB_Matrix C, // input/output matrix for results const GrB_Matrix Mask, // optional mask for C, unused if NULL @@ -4033,7 +4473,7 @@ GrB_Info GrB_eWiseMult_Matrix_Semiring // C = accum (C, A.*B) ) ; GB_PUBLIC -GrB_Info GrB_eWiseMult_Matrix_Monoid // C = accum (C, A.*B) +GrB_Info GrB_Matrix_eWiseMult_Monoid // C = accum (C, A.*B) ( GrB_Matrix C, // input/output matrix for results const GrB_Matrix Mask, // optional mask for C, unused if NULL @@ -4045,7 +4485,7 @@ GrB_Info GrB_eWiseMult_Matrix_Monoid // C = accum (C, A.*B) ) ; GB_PUBLIC -GrB_Info GrB_eWiseMult_Matrix_BinaryOp // C = accum (C, A.*B) +GrB_Info GrB_Matrix_eWiseMult_BinaryOp // C = accum (C, A.*B) ( GrB_Matrix C, // input/output matrix for results const GrB_Matrix Mask, // optional mask for C, unused if NULL @@ -4056,6 +4496,35 @@ GrB_Info GrB_eWiseMult_Matrix_BinaryOp // C = accum (C, A.*B) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; +// misnamed, deprecated functions: These function names do not appear +// in the GraphBLAS C API Specification. They were misnamed in +// earlier versions of SuiteSparse:GraphBLAS. The corrected versions +// appear above. + +GB_PUBLIC GrB_Info GrB_eWiseMult_Vector_Semiring (GrB_Vector, + const GrB_Vector, const GrB_BinaryOp, const GrB_Semiring, + const GrB_Vector, const GrB_Vector, const GrB_Descriptor) ; + +GB_PUBLIC GrB_Info GrB_eWiseMult_Vector_Monoid (GrB_Vector, + const GrB_Vector, const GrB_BinaryOp, const GrB_Monoid, + const GrB_Vector, const GrB_Vector, const GrB_Descriptor desc) ; + +GB_PUBLIC GrB_Info GrB_eWiseMult_Vector_BinaryOp (GrB_Vector, + const GrB_Vector, const GrB_BinaryOp, const GrB_BinaryOp, + const GrB_Vector, const GrB_Vector, const GrB_Descriptor desc) ; + +GB_PUBLIC GrB_Info GrB_eWiseMult_Matrix_Semiring (GrB_Matrix, + const GrB_Matrix, const GrB_BinaryOp, const GrB_Semiring, + const GrB_Matrix, const GrB_Matrix, const GrB_Descriptor desc) ; + +GB_PUBLIC GrB_Info GrB_eWiseMult_Matrix_Monoid (GrB_Matrix, + const GrB_Matrix, const GrB_BinaryOp, const GrB_Monoid, + const GrB_Matrix, const GrB_Matrix, const GrB_Descriptor) ; + +GB_PUBLIC GrB_Info GrB_eWiseMult_Matrix_BinaryOp (GrB_Matrix, + const GrB_Matrix, const GrB_BinaryOp, const GrB_BinaryOp, + const GrB_Matrix, const GrB_Matrix, const GrB_Descriptor desc) ; + // All 6 of the above type-specific functions are captured in a single // type-generic function, GrB_eWiseMult: @@ -4068,23 +4537,23 @@ GrB_Info GrB_eWiseMult_Matrix_BinaryOp // C = accum (C, A.*B) _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_eWiseMult_Matrix_Semiring , \ - GrB_Semiring : GrB_eWiseMult_Matrix_Semiring , \ - const GrB_Monoid : GrB_eWiseMult_Matrix_Monoid , \ - GrB_Monoid : GrB_eWiseMult_Matrix_Monoid , \ - const GrB_BinaryOp : GrB_eWiseMult_Matrix_BinaryOp , \ - GrB_BinaryOp : GrB_eWiseMult_Matrix_BinaryOp \ + const GrB_Semiring : GrB_Matrix_eWiseMult_Semiring , \ + GrB_Semiring : GrB_Matrix_eWiseMult_Semiring , \ + const GrB_Monoid : GrB_Matrix_eWiseMult_Monoid , \ + GrB_Monoid : GrB_Matrix_eWiseMult_Monoid , \ + const GrB_BinaryOp : GrB_Matrix_eWiseMult_BinaryOp , \ + GrB_BinaryOp : GrB_Matrix_eWiseMult_BinaryOp \ ), \ GrB_Vector : \ _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_eWiseMult_Vector_Semiring , \ - GrB_Semiring : GrB_eWiseMult_Vector_Semiring , \ - const GrB_Monoid : GrB_eWiseMult_Vector_Monoid , \ - GrB_Monoid : GrB_eWiseMult_Vector_Monoid , \ - const GrB_BinaryOp : GrB_eWiseMult_Vector_BinaryOp , \ - GrB_BinaryOp : GrB_eWiseMult_Vector_BinaryOp \ + const GrB_Semiring : GrB_Vector_eWiseMult_Semiring , \ + GrB_Semiring : GrB_Vector_eWiseMult_Semiring , \ + const GrB_Monoid : GrB_Vector_eWiseMult_Monoid , \ + GrB_Monoid : GrB_Vector_eWiseMult_Monoid , \ + const GrB_BinaryOp : GrB_Vector_eWiseMult_BinaryOp , \ + GrB_BinaryOp : GrB_Vector_eWiseMult_BinaryOp \ ) \ ) \ (C, Mask, accum, op, A, B, desc) @@ -4103,7 +4572,7 @@ GrB_Info GrB_eWiseMult_Matrix_BinaryOp // C = accum (C, A.*B) // pattern of A and B, then T(i,j) = A(i,j) "+" B(i,j). If only A(i,j) is // present then T(i,j) = A (i,j) and the "+" operator is not used. Likewise, // if only B(i,j) is in the pattern of B but A(i,j) is not in the pattern of A, -// then T(i,j) = B(i,j). This is primary difference between GrB_eWiseAdd and +// then T(i,j) = B(i,j). This is the primary difference between GrB_eWiseAdd and // GrB_eWiseMult; the same set of binary operators can be used in both methods, // and the action they take on entries in the intersection of the pattern of A // and B is identical. @@ -4115,7 +4584,7 @@ GrB_Info GrB_eWiseMult_Matrix_BinaryOp // C = accum (C, A.*B) // operator instead. For a monoid, the mult operator is the monoid operator. GB_PUBLIC -GrB_Info GrB_eWiseAdd_Vector_Semiring // w = accum (w, u+v) +GrB_Info GrB_Vector_eWiseAdd_Semiring // w = accum (w, u+v) ( GrB_Vector w, // input/output vector for results const GrB_Vector mask, // optional mask for w, unused if NULL @@ -4127,7 +4596,7 @@ GrB_Info GrB_eWiseAdd_Vector_Semiring // w = accum (w, u+v) ) ; GB_PUBLIC -GrB_Info GrB_eWiseAdd_Vector_Monoid // w = accum (w, u+v) +GrB_Info GrB_Vector_eWiseAdd_Monoid // w = accum (w, u+v) ( GrB_Vector w, // input/output vector for results const GrB_Vector mask, // optional mask for w, unused if NULL @@ -4139,7 +4608,7 @@ GrB_Info GrB_eWiseAdd_Vector_Monoid // w = accum (w, u+v) ) ; GB_PUBLIC -GrB_Info GrB_eWiseAdd_Vector_BinaryOp // w = accum (w, u+v) +GrB_Info GrB_Vector_eWiseAdd_BinaryOp // w = accum (w, u+v) ( GrB_Vector w, // input/output vector for results const GrB_Vector mask, // optional mask for w, unused if NULL @@ -4151,7 +4620,7 @@ GrB_Info GrB_eWiseAdd_Vector_BinaryOp // w = accum (w, u+v) ) ; GB_PUBLIC -GrB_Info GrB_eWiseAdd_Matrix_Semiring // C = accum (C, A+B) +GrB_Info GrB_Matrix_eWiseAdd_Semiring // C = accum (C, A+B) ( GrB_Matrix C, // input/output matrix for results const GrB_Matrix Mask, // optional mask for C, unused if NULL @@ -4163,7 +4632,7 @@ GrB_Info GrB_eWiseAdd_Matrix_Semiring // C = accum (C, A+B) ) ; GB_PUBLIC -GrB_Info GrB_eWiseAdd_Matrix_Monoid // C = accum (C, A+B) +GrB_Info GrB_Matrix_eWiseAdd_Monoid // C = accum (C, A+B) ( GrB_Matrix C, // input/output matrix for results const GrB_Matrix Mask, // optional mask for C, unused if NULL @@ -4175,7 +4644,7 @@ GrB_Info GrB_eWiseAdd_Matrix_Monoid // C = accum (C, A+B) ) ; GB_PUBLIC -GrB_Info GrB_eWiseAdd_Matrix_BinaryOp // C = accum (C, A+B) +GrB_Info GrB_Matrix_eWiseAdd_BinaryOp // C = accum (C, A+B) ( GrB_Matrix C, // input/output matrix for results const GrB_Matrix Mask, // optional mask for C, unused if NULL @@ -4186,6 +4655,35 @@ GrB_Info GrB_eWiseAdd_Matrix_BinaryOp // C = accum (C, A+B) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; +// misnamed, deprecated functions: These function names do not appear +// in the GraphBLAS C API Specification. They were misnamed in +// earlier versions of SuiteSparse:GraphBLAS. The corrected versions +// appear above. + +GB_PUBLIC GrB_Info GrB_eWiseAdd_Vector_Semiring (GrB_Vector, + const GrB_Vector, const GrB_BinaryOp, const GrB_Semiring, + const GrB_Vector, const GrB_Vector, const GrB_Descriptor desc) ; + +GB_PUBLIC GrB_Info GrB_eWiseAdd_Vector_Monoid (GrB_Vector, + const GrB_Vector, const GrB_BinaryOp, const GrB_Monoid, + const GrB_Vector, const GrB_Vector, const GrB_Descriptor desc) ; + +GB_PUBLIC GrB_Info GrB_eWiseAdd_Vector_BinaryOp (GrB_Vector, + const GrB_Vector, const GrB_BinaryOp, const GrB_BinaryOp, + const GrB_Vector, const GrB_Vector, const GrB_Descriptor) ; + +GB_PUBLIC GrB_Info GrB_eWiseAdd_Matrix_Semiring (GrB_Matrix, + const GrB_Matrix, const GrB_BinaryOp, const GrB_Semiring, + const GrB_Matrix, const GrB_Matrix, const GrB_Descriptor) ; + +GB_PUBLIC GrB_Info GrB_eWiseAdd_Matrix_Monoid (GrB_Matrix, + const GrB_Matrix, const GrB_BinaryOp, const GrB_Monoid, + const GrB_Matrix, const GrB_Matrix, const GrB_Descriptor) ; + +GB_PUBLIC GrB_Info GrB_eWiseAdd_Matrix_BinaryOp (GrB_Matrix, + const GrB_Matrix, const GrB_BinaryOp, const GrB_BinaryOp, + const GrB_Matrix, const GrB_Matrix, const GrB_Descriptor) ; + #if GxB_STDC_VERSION >= 201112L #define GrB_eWiseAdd(C,Mask,accum,op,A,B,desc) \ _Generic \ @@ -4195,23 +4693,23 @@ GrB_Info GrB_eWiseAdd_Matrix_BinaryOp // C = accum (C, A+B) _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_eWiseAdd_Matrix_Semiring , \ - GrB_Semiring : GrB_eWiseAdd_Matrix_Semiring , \ - const GrB_Monoid : GrB_eWiseAdd_Matrix_Monoid , \ - GrB_Monoid : GrB_eWiseAdd_Matrix_Monoid , \ - const GrB_BinaryOp : GrB_eWiseAdd_Matrix_BinaryOp , \ - GrB_BinaryOp : GrB_eWiseAdd_Matrix_BinaryOp \ + const GrB_Semiring : GrB_Matrix_eWiseAdd_Semiring , \ + GrB_Semiring : GrB_Matrix_eWiseAdd_Semiring , \ + const GrB_Monoid : GrB_Matrix_eWiseAdd_Monoid , \ + GrB_Monoid : GrB_Matrix_eWiseAdd_Monoid , \ + const GrB_BinaryOp : GrB_Matrix_eWiseAdd_BinaryOp , \ + GrB_BinaryOp : GrB_Matrix_eWiseAdd_BinaryOp \ ), \ GrB_Vector : \ _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_eWiseAdd_Vector_Semiring , \ - GrB_Semiring : GrB_eWiseAdd_Vector_Semiring , \ - const GrB_Monoid : GrB_eWiseAdd_Vector_Monoid , \ - GrB_Monoid : GrB_eWiseAdd_Vector_Monoid , \ - const GrB_BinaryOp : GrB_eWiseAdd_Vector_BinaryOp , \ - GrB_BinaryOp : GrB_eWiseAdd_Vector_BinaryOp \ + const GrB_Semiring : GrB_Vector_eWiseAdd_Semiring , \ + GrB_Semiring : GrB_Vector_eWiseAdd_Semiring , \ + const GrB_Monoid : GrB_Vector_eWiseAdd_Monoid , \ + GrB_Monoid : GrB_Vector_eWiseAdd_Monoid , \ + const GrB_BinaryOp : GrB_Vector_eWiseAdd_BinaryOp , \ + GrB_BinaryOp : GrB_Vector_eWiseAdd_BinaryOp \ ) \ ) \ (C, Mask, accum, op, A, B, desc) @@ -4355,7 +4853,7 @@ GrB_Info GrB_Col_extract // w = accum (w, A(I,j)) // (1) the mask in the GxB_subassign functions has the same dimensions as // w(I) for vectors and C(I,J) for matrices. In GrB_assign, the mask is -// the same size as w or C, respectively (except for GrB_Row_asssign and +// the same size as w or C, respectively (except for GrB_Row_assign and // GrB_Col_assign, in which case the mask is the same size as a row or // column of C, respectively). The two masks are related. If M is the // mask for GrB_assign, then M(I,J) is the mask for GxB_subassign. If @@ -4648,6 +5146,30 @@ GrB_Info GxB_Vector_subassign_FP64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; +GB_PUBLIC +GrB_Info GxB_Vector_subassign_FC32 // w(I) = accum (w(I),x) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w(I), unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(w(I),x) + GxB_FC32_t x, // scalar to assign to w(I) + const GrB_Index *I, // row indices + GrB_Index ni, // number of row indices + const GrB_Descriptor desc // descriptor for w(I) and mask +) ; + +GB_PUBLIC +GrB_Info GxB_Vector_subassign_FC64 // w(I) = accum (w(I),x) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w(I), unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(w(I),x) + GxB_FC64_t x, // scalar to assign to w(I) + const GrB_Index *I, // row indices + GrB_Index ni, // number of row indices + const GrB_Descriptor desc // descriptor for w(I) and mask +) ; + GB_PUBLIC GrB_Info GxB_Vector_subassign_UDT // w(I) = accum (w(I),x) ( @@ -4825,12 +5347,12 @@ GrB_Info GxB_Matrix_subassign_FP64 // C(I,J) = accum (C(I,J),x) ) ; GB_PUBLIC -GrB_Info GxB_Matrix_subassign_UDT // C(I,J) = accum (C(I,J),x) +GrB_Info GxB_Matrix_subassign_FC32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results const GrB_Matrix Mask, // optional mask for C(I,J), unused if NULL const GrB_BinaryOp accum, // optional accum for Z=accum(C(I,J),x) - void *x, // scalar to assign to C(I,J) + GxB_FC32_t x, // scalar to assign to C(I,J) const GrB_Index *I, // row indices GrB_Index ni, // number of row indices const GrB_Index *J, // column indices @@ -4838,102 +5360,84 @@ GrB_Info GxB_Matrix_subassign_UDT // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -//------------------------------------------------------------------------------ -// GxB_subassign: generic submatrix/subvector assignment -//------------------------------------------------------------------------------ - -// GxB_subassign is a generic function that provides access to all specific -// GxB_*_subassign* functions: - -// GxB_Vector_subassign (w,m,acc,u,I,ni,d) // w(I) =acc(w(I),u) -// GxB_Matrix_subassign (C,M,acc,A,I,ni,J,nj,d)// C(I,J) =acc(C(I,J),A) -// GxB_Col_subassign (C,m,acc,u,I,ni,j,d) // C(I,j) =acc(C(I,j),u) -// GxB_Row_subassign (C,m,acc,u,i,J,nj,d) // C(i,J)=acc(C(i,J),u') -// GxB_Vector_subassign_T (w,m,acc,x,I,ni,d) // w(I) =acc(w(I),x) -// GxB_Matrix_subassign_T (C,M,acc,x,I,ni,J,nj,d)// C(I,J) =acc(C(I,J),x) +GB_PUBLIC +GrB_Info GxB_Matrix_subassign_FC64 // C(I,J) = accum (C(I,J),x) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C(I,J), unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C(I,J),x) + GxB_FC64_t x, // scalar to assign to C(I,J) + const GrB_Index *I, // row indices + GrB_Index ni, // number of row indices + const GrB_Index *J, // column indices + GrB_Index nj, // number of column indices + const GrB_Descriptor desc // descriptor for C(I,J) and Mask +) ; + +GB_PUBLIC +GrB_Info GxB_Matrix_subassign_UDT // C(I,J) = accum (C(I,J),x) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C(I,J), unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C(I,J),x) + void *x, // scalar to assign to C(I,J) + const GrB_Index *I, // row indices + GrB_Index ni, // number of row indices + const GrB_Index *J, // column indices + GrB_Index nj, // number of column indices + const GrB_Descriptor desc // descriptor for C(I,J) and Mask +) ; + +//------------------------------------------------------------------------------ +// GxB_subassign: generic submatrix/subvector assignment +//------------------------------------------------------------------------------ + +// GxB_subassign is a generic function that provides access to all specific +// GxB_*_subassign* functions: + +// GxB_Vector_subassign (w,m,acc,u,I,ni,d) // w(I) = acc(w(I),u) +// GxB_Matrix_subassign (C,M,acc,A,I,ni,J,nj,d) // C(I,J) = acc(C(I,J),A) +// GxB_Col_subassign (C,m,acc,u,I,ni,j,d) // C(I,j) = acc(C(I,j),u) +// GxB_Row_subassign (C,m,acc,u,i,J,nj,d) // C(i,J) = acc(C(i,J),u') +// GxB_Vector_subassign_T (w,m,acc,x,I,ni,d) // w(I) = acc(w(I),x) +// GxB_Matrix_subassign_T (C,M,acc,x,I,ni,J,nj,d) // C(I,J) = acc(C(I,J),x) #if GxB_STDC_VERSION >= 201112L #define GxB_subassign(arg1,Mask,accum,arg4,arg5,...) \ - _Generic \ - ( \ - (arg1), \ - GrB_Vector : \ - _Generic \ - ( \ - (arg4), \ - const bool : GxB_Vector_subassign_BOOL , \ - bool : GxB_Vector_subassign_BOOL , \ - const int8_t : GxB_Vector_subassign_INT8 , \ - int8_t : GxB_Vector_subassign_INT8 , \ - const uint8_t : GxB_Vector_subassign_UINT8 , \ - uint8_t : GxB_Vector_subassign_UINT8 , \ - const int16_t : GxB_Vector_subassign_INT16 , \ - int16_t : GxB_Vector_subassign_INT16 , \ - const uint16_t : GxB_Vector_subassign_UINT16 , \ - uint16_t : GxB_Vector_subassign_UINT16 , \ - const int32_t : GxB_Vector_subassign_INT32 , \ - int32_t : GxB_Vector_subassign_INT32 , \ - const uint32_t : GxB_Vector_subassign_UINT32 , \ - uint32_t : GxB_Vector_subassign_UINT32 , \ - const int64_t : GxB_Vector_subassign_INT64 , \ - int64_t : GxB_Vector_subassign_INT64 , \ - const uint64_t : GxB_Vector_subassign_UINT64 , \ - uint64_t : GxB_Vector_subassign_UINT64 , \ - const float : GxB_Vector_subassign_FP32 , \ - float : GxB_Vector_subassign_FP32 , \ - const double : GxB_Vector_subassign_FP64 , \ - double : GxB_Vector_subassign_FP64 , \ - const void * : GxB_Vector_subassign_UDT , \ - void * : GxB_Vector_subassign_UDT , \ - default : GxB_Vector_subassign \ - ), \ - default : \ - _Generic \ - ( \ - (arg4), \ - const bool : GxB_Matrix_subassign_BOOL , \ - bool : GxB_Matrix_subassign_BOOL , \ - const int8_t : GxB_Matrix_subassign_INT8 , \ - int8_t : GxB_Matrix_subassign_INT8 , \ - const uint8_t : GxB_Matrix_subassign_UINT8 , \ - uint8_t : GxB_Matrix_subassign_UINT8 , \ - const int16_t : GxB_Matrix_subassign_INT16 , \ - int16_t : GxB_Matrix_subassign_INT16 , \ - const uint16_t : GxB_Matrix_subassign_UINT16 , \ - uint16_t : GxB_Matrix_subassign_UINT16 , \ - const int32_t : GxB_Matrix_subassign_INT32 , \ - int32_t : GxB_Matrix_subassign_INT32 , \ - const uint32_t : GxB_Matrix_subassign_UINT32 , \ - uint32_t : GxB_Matrix_subassign_UINT32 , \ - const int64_t : GxB_Matrix_subassign_INT64 , \ - int64_t : GxB_Matrix_subassign_INT64 , \ - const uint64_t : GxB_Matrix_subassign_UINT64 , \ - uint64_t : GxB_Matrix_subassign_UINT64 , \ - const float : GxB_Matrix_subassign_FP32 , \ - float : GxB_Matrix_subassign_FP32 , \ - const double : GxB_Matrix_subassign_FP64 , \ - double : GxB_Matrix_subassign_FP64 , \ - const void * : GxB_Matrix_subassign_UDT , \ - void * : GxB_Matrix_subassign_UDT , \ - const GrB_Vector : \ - _Generic \ - ( \ - (arg5), \ + _Generic \ + ( \ + (arg1), \ + GrB_Vector : \ + _Generic \ + ( \ + (arg4), \ + GB_(, GxB, Vector_subassign) , \ + default : GxB_Vector_subassign \ + ), \ + default : \ + _Generic \ + ( \ + (arg4), \ + GB_(, GxB, Matrix_subassign) , \ + const GrB_Vector : \ + _Generic \ + ( \ + (arg5), \ const GrB_Index *: GxB_Col_subassign , \ GrB_Index *: GxB_Col_subassign , \ default : GxB_Row_subassign \ - ), \ - GrB_Vector : \ - _Generic \ - ( \ - (arg5), \ + ), \ + GrB_Vector : \ + _Generic \ + ( \ + (arg5), \ const GrB_Index *: GxB_Col_subassign , \ GrB_Index *: GxB_Col_subassign , \ default : GxB_Row_subassign \ - ), \ + ), \ default : GxB_Matrix_subassign \ - ) \ - ) \ + ) \ + ) \ (arg1, Mask, accum, arg4, arg5, __VA_ARGS__) #endif @@ -5138,6 +5642,30 @@ GrB_Info GrB_Vector_assign_FP64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; +GB_PUBLIC +GrB_Info GxB_Vector_assign_FC32 // w(I) = accum (w(I),x) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(w(I),x) + GxB_FC32_t x, // scalar to assign to w(I) + const GrB_Index *I, // row indices + GrB_Index ni, // number of row indices + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GxB_Vector_assign_FC64 // w(I) = accum (w(I),x) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(w(I),x) + GxB_FC64_t x, // scalar to assign to w(I) + const GrB_Index *I, // row indices + GrB_Index ni, // number of row indices + const GrB_Descriptor desc // descriptor for w and mask +) ; + GB_PUBLIC GrB_Info GrB_Vector_assign_UDT // w(I) = accum (w(I),x) ( @@ -5314,6 +5842,34 @@ GrB_Info GrB_Matrix_assign_FP64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; +GB_PUBLIC +GrB_Info GxB_Matrix_assign_FC32 // C(I,J) = accum (C(I,J),x) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C(I,J),x) + GxB_FC32_t x, // scalar to assign to C(I,J) + const GrB_Index *I, // row indices + GrB_Index ni, // number of row indices + const GrB_Index *J, // column indices + GrB_Index nj, // number of column indices + const GrB_Descriptor desc // descriptor for C and Mask +) ; + +GB_PUBLIC +GrB_Info GxB_Matrix_assign_FC64 // C(I,J) = accum (C(I,J),x) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C(I,J),x) + GxB_FC64_t x, // scalar to assign to C(I,J) + const GrB_Index *I, // row indices + GrB_Index ni, // number of row indices + const GrB_Index *J, // column indices + GrB_Index nj, // number of column indices + const GrB_Descriptor desc // descriptor for C and Mask +) ; + GB_PUBLIC GrB_Info GrB_Matrix_assign_UDT // C(I,J) = accum (C(I,J),x) ( @@ -5335,12 +5891,12 @@ GrB_Info GrB_Matrix_assign_UDT // C(I,J) = accum (C(I,J),x) // GrB_assign is a generic function that provides access to all specific // GrB_*_assign* functions: -// GrB_Vector_assign (w,mask,acc,u,I,ni,d) // w(I) =acc(w(I),u) -// GrB_Matrix_assign (C,Mask,acc,A,I,ni,J,nj,d)// C(I,J) =acc(C(I,J),A) -// GrB_Col_assign (C,mask,acc,u,I,ni,j,d) // C(I,j) =acc(C(I,j),u) -// GrB_Row_assign (C,mask,acc,u,i,J,nj,d) // C(i,J)=acc(C(i,J),u') -// GrB_Vector_assign_T (w,mask,acc,x,I,ni,d) // w(I) =acc(w(I),x) -// GrB_Matrix_assign_T (C,Mask,acc,x,I,ni,J,nj,d)// C(I,J) =acc(C(I,J),x) +// GrB_Vector_assign (w,m,acc,u,I,ni,d) // w(I) = acc(w(I),u) +// GrB_Matrix_assign (C,M,acc,A,I,ni,J,nj,d) // C(I,J) = acc(C(I,J),A) +// GrB_Col_assign (C,m,acc,u,I,ni,j,d) // C(I,j) = acc(C(I,j),u) +// GrB_Row_assign (C,m,acc,u,i,J,nj,d) // C(i,J) = acc(C(i,J),u') +// GrB_Vector_assign_T (w,m,acc,x,I,ni,d) // w(I) = acc(w(I),x) +// GrB_Matrix_assign_T (C,M,acc,x,I,ni,J,nj,d) // C(I,J) = acc(C(I,J),x) #if GxB_STDC_VERSION >= 201112L #define GrB_assign(arg1,Mask,accum,arg4,arg5,...) \ @@ -5351,60 +5907,14 @@ GrB_Info GrB_Matrix_assign_UDT // C(I,J) = accum (C(I,J),x) _Generic \ ( \ (arg4), \ - const bool : GrB_Vector_assign_BOOL , \ - bool : GrB_Vector_assign_BOOL , \ - const int8_t : GrB_Vector_assign_INT8 , \ - int8_t : GrB_Vector_assign_INT8 , \ - const uint8_t : GrB_Vector_assign_UINT8 , \ - uint8_t : GrB_Vector_assign_UINT8 , \ - const int16_t : GrB_Vector_assign_INT16 , \ - int16_t : GrB_Vector_assign_INT16 , \ - const uint16_t : GrB_Vector_assign_UINT16 , \ - uint16_t : GrB_Vector_assign_UINT16 , \ - const int32_t : GrB_Vector_assign_INT32 , \ - int32_t : GrB_Vector_assign_INT32 , \ - const uint32_t : GrB_Vector_assign_UINT32 , \ - uint32_t : GrB_Vector_assign_UINT32 , \ - const int64_t : GrB_Vector_assign_INT64 , \ - int64_t : GrB_Vector_assign_INT64 , \ - const uint64_t : GrB_Vector_assign_UINT64 , \ - uint64_t : GrB_Vector_assign_UINT64 , \ - const float : GrB_Vector_assign_FP32 , \ - float : GrB_Vector_assign_FP32 , \ - const double : GrB_Vector_assign_FP64 , \ - double : GrB_Vector_assign_FP64 , \ - const void * : GrB_Vector_assign_UDT , \ - void * : GrB_Vector_assign_UDT , \ - default : GrB_Vector_assign \ + GB_(, GrB, Vector_assign) , \ + default : GrB_Vector_assign \ ), \ default : \ _Generic \ ( \ (arg4), \ - const bool : GrB_Matrix_assign_BOOL , \ - bool : GrB_Matrix_assign_BOOL , \ - const int8_t : GrB_Matrix_assign_INT8 , \ - int8_t : GrB_Matrix_assign_INT8 , \ - const uint8_t : GrB_Matrix_assign_UINT8 , \ - uint8_t : GrB_Matrix_assign_UINT8 , \ - const int16_t : GrB_Matrix_assign_INT16 , \ - int16_t : GrB_Matrix_assign_INT16 , \ - const uint16_t : GrB_Matrix_assign_UINT16 , \ - uint16_t : GrB_Matrix_assign_UINT16 , \ - const int32_t : GrB_Matrix_assign_INT32 , \ - int32_t : GrB_Matrix_assign_INT32 , \ - const uint32_t : GrB_Matrix_assign_UINT32 , \ - uint32_t : GrB_Matrix_assign_UINT32 , \ - const int64_t : GrB_Matrix_assign_INT64 , \ - int64_t : GrB_Matrix_assign_INT64 , \ - const uint64_t : GrB_Matrix_assign_UINT64 , \ - uint64_t : GrB_Matrix_assign_UINT64 , \ - const float : GrB_Matrix_assign_FP32 , \ - float : GrB_Matrix_assign_FP32 , \ - const double : GrB_Matrix_assign_FP64 , \ - double : GrB_Matrix_assign_FP64 , \ - const void * : GrB_Matrix_assign_UDT , \ - void * : GrB_Matrix_assign_UDT , \ + GB_(, GrB, Matrix_assign) , \ const GrB_Vector : \ _Generic \ ( \ @@ -5427,34 +5937,782 @@ GrB_Info GrB_Matrix_assign_UDT // C(I,J) = accum (C(I,J),x) (arg1, Mask, accum, arg4, arg5, __VA_ARGS__) #endif -//------------------------------------------------------------------------------ -// matrix and vector apply -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +// matrix and vector apply +//------------------------------------------------------------------------------ + +// Apply a unary operator to the entries in a matrix or vector, +// C = accum (C, op (A)). + +// The input matrix A may be optionally transposed first, via the descriptor. + +GB_PUBLIC +GrB_Info GrB_Vector_apply // w = accum (w, op(u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_UnaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply // C = accum (C, op(A)) or op(A') +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_UnaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +//------------------------------------------- +// vector apply: binaryop variants (bind 1st) +//------------------------------------------- + +// Apply a binary operator to the entries in a vector, binding the first +// input to a scalar x, w = accum (w, op (x,u)). + +GB_PUBLIC +GrB_Info GxB_Vector_apply_BinaryOp1st // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GxB_Scalar x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp1st_BOOL // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + bool x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp1st_INT8 // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + int8_t x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp1st_INT16 // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + int16_t x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp1st_INT32 // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + int32_t x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp1st_INT64 // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + int64_t x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp1st_UINT8 // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + uint8_t x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp1st_UINT16 // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + uint16_t x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp1st_UINT32 // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + uint32_t x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp1st_UINT64 // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + uint64_t x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp1st_FP32 // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + float x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp1st_FP64 // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + double x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GxB_Vector_apply_BinaryOp1st_FC32 // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + GxB_FC32_t x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GxB_Vector_apply_BinaryOp1st_FC64 // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + GxB_FC64_t x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp1st_UDT // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const void *x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; + +//------------------------------------------- +// vector apply: binaryop variants (bind 2nd) +//------------------------------------------- + +// Apply a binary operator to the entries in a vector, binding the second +// input to a scalar y, w = accum (w, op (u,y)). + +GB_PUBLIC +GrB_Info GxB_Vector_apply_BinaryOp2nd // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + const GxB_Scalar y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp2nd_BOOL // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + bool y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp2nd_INT8 // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + int8_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp2nd_INT16 // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + int16_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp2nd_INT32 // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + int32_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp2nd_INT64 // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + int64_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT8 // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + uint8_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT16 // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + uint16_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT32 // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + uint32_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT64 // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + uint64_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp2nd_FP32 // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + float y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp2nd_FP64 // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + double y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GxB_Vector_apply_BinaryOp2nd_FC32 // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + GxB_FC32_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GxB_Vector_apply_BinaryOp2nd_FC64 // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + GxB_FC64_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_apply_BinaryOp2nd_UDT // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + const void *y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; + +//------------------------------------------- +// matrix apply: binaryop variants (bind 1st) +//------------------------------------------- + +// Apply a binary operator to the entries in a matrix, binding the first input +// to a scalar x, C = accum (C, op (x,A)), or op(x,A'). + +GB_PUBLIC +GrB_Info GxB_Matrix_apply_BinaryOp1st // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GxB_Scalar x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp1st_BOOL // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + bool x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp1st_INT8 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + int8_t x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp1st_INT16 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + int16_t x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp1st_INT32 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + int32_t x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp1st_INT64 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + int64_t x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT8 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + uint8_t x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT16 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + uint16_t x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT32 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + uint32_t x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT64 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + uint64_t x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp1st_FP32 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + float x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp1st_FP64 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + double x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GxB_Matrix_apply_BinaryOp1st_FC32 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + GxB_FC32_t x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GxB_Matrix_apply_BinaryOp1st_FC64 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + GxB_FC64_t x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp1st_UDT // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const void *x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +//------------------------------------------- +// matrix apply: binaryop variants (bind 2nd) +//------------------------------------------- + +// Apply a binary operator to the entries in a matrix, binding the second input +// to a scalar y, C = accum (C, op (A,y)), or op(A',y). + +GB_PUBLIC +GrB_Info GxB_Matrix_apply_BinaryOp2nd // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + const GxB_Scalar y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp2nd_BOOL // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + bool y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT8 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + int8_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT16 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + int16_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT32 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + int32_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT64 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + int64_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT8 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + uint8_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT16 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + uint16_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT32 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + uint32_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT64 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + uint64_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp2nd_FP32 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + float y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; -// Apply a unary operator to the entries in a matrix or vector, -// C = accum (C, op (A)). +GB_PUBLIC +GrB_Info GrB_Matrix_apply_BinaryOp2nd_FP64 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + double y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; -// The input matrix A may be optionally transposed first, via the descriptor. +GB_PUBLIC +GrB_Info GxB_Matrix_apply_BinaryOp2nd_FC32 // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + GxB_FC32_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; GB_PUBLIC -GrB_Info GrB_Vector_apply // w = accum (w, op(u)) +GrB_Info GxB_Matrix_apply_BinaryOp2nd_FC64 // C=accum(C,op(x,A)) ( - GrB_Vector w, // input/output vector for results - const GrB_Vector mask, // optional mask for w, unused if NULL - const GrB_BinaryOp accum, // optional accum for z=accum(w,t) - const GrB_UnaryOp op, // operator to apply to the entries - const GrB_Vector u, // first input: vector u - const GrB_Descriptor desc // descriptor for w and mask + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + GxB_FC64_t y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A ) ; GB_PUBLIC -GrB_Info GrB_Matrix_apply // C = accum (C, op(A)) or op(A') +GrB_Info GrB_Matrix_apply_BinaryOp2nd_UDT // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results const GrB_Matrix Mask, // optional mask for C, unused if NULL const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) - const GrB_UnaryOp op, // operator to apply to the entries + const GrB_BinaryOp op, // operator to apply to the entries const GrB_Matrix A, // first input: matrix A + const void *y, // second input: scalar y const GrB_Descriptor desc // descriptor for C, mask, and A ) ; @@ -5468,15 +6726,57 @@ GrB_Info GrB_Matrix_apply // C = accum (C, op(A)) or op(A') // GrB_Vector_apply (w,mask,acc,op,u,d) // w = accum (w, op(u)) // GrB_Matrix_apply (C,Mask,acc,op,A,d) // C = accum (C, op(A)) +// It has been extended in the v1.3 spec to binary operators: + +// GrB_Vector_apply (w,m,acc,unop ,u,d) +// GxB_Vector_apply_BinaryOp1st (w,m,acc,binop,x,u,d) +// GrB_Vector_apply_BinaryOp1st_TYPE (w,m,acc,binop,x,u,d) +// GxB_Vector_apply_BinaryOp2nd (w,m,acc,binop,u,y,d) +// GrB_Vector_apply_BinaryOp2nd_TYPE (w,m,acc,binop,u,y,d) + +// GrB_Matrix_apply (C,M,acc,unop ,A,d) +// GxB_Matrix_apply_BinaryOp1st (C,M,acc,binop,x,A,d) +// GrB_Matrix_apply_BinaryOp1st_TYPE (C,M,acc,binop,x,A,d) +// GxB_Matrix_apply_BinaryOp2nd (C,M,acc,binop,A,y,d) +// GrB_Matrix_apply_BinaryOp2nd_TYPE (C,M,acc,binop,A,y,d) + #if GxB_STDC_VERSION >= 201112L -#define GrB_apply(C,Mask,accum,op,A,desc) \ - _Generic \ - ( \ - (C), \ - GrB_Vector : GrB_Vector_apply , \ - GrB_Matrix : GrB_Matrix_apply \ - ) \ - (C, Mask, accum, op, A, desc) + +#define GB_BIND(kind,x,y,...) \ + _Generic \ + ( \ + (x), \ + GxB_Scalar: GxB_ ## kind ## _apply_BinaryOp1st , \ + GB_(, GrB, kind ## _apply_BinaryOp1st) , \ + default : \ + _Generic \ + ( \ + (y), \ + default : GxB_ ## kind ## _apply_BinaryOp2nd , \ + GB_(, GrB, kind ## _apply_BinaryOp2nd) \ + ) \ + ) + +#define GrB_apply(C,Mask,accum,op,...) \ + _Generic \ + ( \ + (C), \ + GrB_Vector : \ + _Generic \ + ( \ + (op), \ + GrB_UnaryOp : GrB_Vector_apply , \ + GrB_BinaryOp : GB_BIND (Vector, __VA_ARGS__) \ + ), \ + GrB_Matrix : \ + _Generic \ + ( \ + (op), \ + GrB_UnaryOp : GrB_Matrix_apply , \ + GrB_BinaryOp : GB_BIND (Matrix, __VA_ARGS__) \ + ) \ + ) \ + (C, Mask, accum, op, __VA_ARGS__) #endif //------------------------------------------------------------------------------ @@ -5698,6 +6998,26 @@ GrB_Info GrB_Vector_reduce_FP64 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc // descriptor (currently unused) ) ; +GB_PUBLIC +GrB_Info GxB_Vector_reduce_FC32 // c = accum (c, reduce_to_scalar (u)) +( + GxB_FC32_t *c, // result scalar + const GrB_BinaryOp accum, // optional accum for c=accum(c,t) + const GrB_Monoid monoid, // monoid to do the reduction + const GrB_Vector u, // vector to reduce + const GrB_Descriptor desc // descriptor (currently unused) +) ; + +GB_PUBLIC +GrB_Info GxB_Vector_reduce_FC64 // c = accum (c, reduce_to_scalar (u)) +( + GxB_FC64_t *c, // result scalar + const GrB_BinaryOp accum, // optional accum for c=accum(c,t) + const GrB_Monoid monoid, // monoid to do the reduction + const GrB_Vector u, // vector to reduce + const GrB_Descriptor desc // descriptor (currently unused) +) ; + GB_PUBLIC GrB_Info GrB_Vector_reduce_UDT // c = accum (c, reduce_to_scalar (u)) ( @@ -5832,6 +7152,26 @@ GrB_Info GrB_Matrix_reduce_FP64 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc // descriptor (currently unused) ) ; +GB_PUBLIC +GrB_Info GxB_Matrix_reduce_FC32 // c = accum (c, reduce_to_scalar (A)) +( + GxB_FC32_t *c, // result scalar + const GrB_BinaryOp accum, // optional accum for c=accum(c,t) + const GrB_Monoid monoid, // monoid to do the reduction + const GrB_Matrix A, // matrix to reduce + const GrB_Descriptor desc // descriptor (currently unused) +) ; + +GB_PUBLIC +GrB_Info GxB_Matrix_reduce_FC64 // c = accum (c, reduce_to_scalar (A)) +( + GxB_FC64_t *c, // result scalar + const GrB_BinaryOp accum, // optional accum for c=accum(c,t) + const GrB_Monoid monoid, // monoid to do the reduction + const GrB_Matrix A, // matrix to reduce + const GrB_Descriptor desc // descriptor (currently unused) +) ; + GB_PUBLIC GrB_Info GrB_Matrix_reduce_UDT // c = accum (c, reduce_to_scalar (A)) ( @@ -5857,83 +7197,27 @@ GrB_Info GrB_Matrix_reduce_UDT // c = accum (c, reduce_to_scalar (A)) // GrB_Matrix_reduce_[SCALAR] (c,acc,monoid,A,d) // c = acc (c,reduce(A)) #if GxB_STDC_VERSION >= 201112L -#define GrB_reduce(arg1,arg2,arg3,arg4,...) \ - _Generic \ - ( \ - (arg4), \ - const GrB_Vector : \ - _Generic \ - ( \ - (arg1), \ - bool * : GrB_Vector_reduce_BOOL , \ - int8_t * : GrB_Vector_reduce_INT8 , \ - uint8_t * : GrB_Vector_reduce_UINT8 , \ - int16_t * : GrB_Vector_reduce_INT16 , \ - uint16_t * : GrB_Vector_reduce_UINT16 , \ - int32_t * : GrB_Vector_reduce_INT32 , \ - uint32_t * : GrB_Vector_reduce_UINT32 , \ - int64_t * : GrB_Vector_reduce_INT64 , \ - uint64_t * : GrB_Vector_reduce_UINT64 , \ - float * : GrB_Vector_reduce_FP32 , \ - double * : GrB_Vector_reduce_FP64 , \ - default : GrB_Vector_reduce_UDT \ - ), \ - GrB_Vector : \ - _Generic \ - ( \ - (arg1), \ - bool * : GrB_Vector_reduce_BOOL , \ - int8_t * : GrB_Vector_reduce_INT8 , \ - uint8_t * : GrB_Vector_reduce_UINT8 , \ - int16_t * : GrB_Vector_reduce_INT16 , \ - uint16_t * : GrB_Vector_reduce_UINT16 , \ - int32_t * : GrB_Vector_reduce_INT32 , \ - uint32_t * : GrB_Vector_reduce_UINT32 , \ - int64_t * : GrB_Vector_reduce_INT64 , \ - uint64_t * : GrB_Vector_reduce_UINT64 , \ - float * : GrB_Vector_reduce_FP32 , \ - double * : GrB_Vector_reduce_FP64 , \ - default : GrB_Vector_reduce_UDT \ - ), \ - const GrB_Matrix : \ - _Generic \ - ( \ - (arg1), \ - bool * : GrB_Matrix_reduce_BOOL , \ - int8_t * : GrB_Matrix_reduce_INT8 , \ - uint8_t * : GrB_Matrix_reduce_UINT8 , \ - int16_t * : GrB_Matrix_reduce_INT16 , \ - uint16_t * : GrB_Matrix_reduce_UINT16 , \ - int32_t * : GrB_Matrix_reduce_INT32 , \ - uint32_t * : GrB_Matrix_reduce_UINT32 , \ - int64_t * : GrB_Matrix_reduce_INT64 , \ - uint64_t * : GrB_Matrix_reduce_UINT64 , \ - float * : GrB_Matrix_reduce_FP32 , \ - double * : GrB_Matrix_reduce_FP64 , \ - default : GrB_Matrix_reduce_UDT \ - ), \ - GrB_Matrix : \ - _Generic \ - ( \ - (arg1), \ - bool * : GrB_Matrix_reduce_BOOL , \ - int8_t * : GrB_Matrix_reduce_INT8 , \ - uint8_t * : GrB_Matrix_reduce_UINT8 , \ - int16_t * : GrB_Matrix_reduce_INT16 , \ - uint16_t * : GrB_Matrix_reduce_UINT16 , \ - int32_t * : GrB_Matrix_reduce_INT32 , \ - uint32_t * : GrB_Matrix_reduce_UINT32 , \ - int64_t * : GrB_Matrix_reduce_INT64 , \ - uint64_t * : GrB_Matrix_reduce_UINT64 , \ - float * : GrB_Matrix_reduce_FP32 , \ - double * : GrB_Matrix_reduce_FP64 , \ - default : GrB_Matrix_reduce_UDT \ - ), \ - const GrB_Monoid : GrB_Matrix_reduce_Monoid , \ - GrB_Monoid : GrB_Matrix_reduce_Monoid , \ - const GrB_BinaryOp : GrB_Matrix_reduce_BinaryOp , \ - GrB_BinaryOp : GrB_Matrix_reduce_BinaryOp \ - ) \ +#define GB_REDUCE_TO_SCALAR(kind,c) \ + _Generic \ + ( \ + (c), \ + GB_(*, GrB, kind ## _reduce), \ + default: GrB_ ## kind ## _reduce_UDT \ + ) + +#define GrB_reduce(arg1,arg2,arg3,arg4,...) \ + _Generic \ + ( \ + (arg4), \ + const GrB_Vector : GB_REDUCE_TO_SCALAR (Vector, arg1), \ + GrB_Vector : GB_REDUCE_TO_SCALAR (Vector, arg1), \ + const GrB_Matrix : GB_REDUCE_TO_SCALAR (Matrix, arg1), \ + GrB_Matrix : GB_REDUCE_TO_SCALAR (Matrix, arg1), \ + const GrB_Monoid : GrB_Matrix_reduce_Monoid , \ + GrB_Monoid : GrB_Matrix_reduce_Monoid , \ + const GrB_BinaryOp : GrB_Matrix_reduce_BinaryOp , \ + GrB_BinaryOp : GrB_Matrix_reduce_BinaryOp \ + ) \ (arg1, arg2, arg3, arg4, __VA_ARGS__) #endif @@ -5961,20 +7245,35 @@ GrB_Info GrB_transpose // C = accum (C, A') // additional predefined objects //============================================================================== -// SPEC: predefined monoids and semirings are extensions to the spec +// SPEC: predefined monoids and semirings are extensions to the spec. +// The v1.3 spec added many GrB_*_MONOIDs; these are listed below. +// Prior GxB_* monoids are kept for backward compatbility. //------------------------------------------------------------------------------ // built-in monoids //------------------------------------------------------------------------------ -// 55 monoids can be constructed using built-in types and operators, all of -// which are defined below. Five operators (min, max, plus, times, any) are -// available for each of the 10 non-Boolean types, plus five purely Boolean -// monoids are available. +// 77 monoids constructed using built-in types and operators are defined below. +// Five operators (min, max, plus, times, any) are available for each of the 10 +// real non-Boolean types, plus five purely Boolean monoids are available. +// Three operators (plus, times, any) are available for both complex types. +// Sixteen monoids are pre-defined for bitwise operators (only for unsigned +// integers). + +// 44 pre-defined monoids now appear with GrB_* names in the v1.3 C API. +// These are identical to the 44 GxB* monoids listed below, just with different +// names. The GrB* names are preferred. + +// Bitwise monoids can be constructed for signed integer types, but these are +// not well-defined by the ANSI C specification, so they are excluded from the +// pre-defined monoids in SuiteSparse:GraphBLAS. GB_PUBLIC GrB_Monoid - // MIN monoids: + //-------------------------------------------------------------------------- + // 10 MIN monoids: (not for complex types) + //-------------------------------------------------------------------------- + GxB_MIN_INT8_MONOID, // identity: INT8_MAX terminal: INT8_MIN GxB_MIN_INT16_MONOID, // identity: INT16_MAX terminal: INT16_MIN GxB_MIN_INT32_MONOID, // identity: INT32_MAX terminal: INT32_MIN @@ -5986,7 +7285,23 @@ GB_PUBLIC GrB_Monoid GxB_MIN_FP32_MONOID, // identity: INFINITY terminal: -INFINITY GxB_MIN_FP64_MONOID, // identity: INFINITY terminal: -INFINITY - // MAX monoids: + // all of the MIN monoids are now in the v1.3 spec with GrB_* names. + // The are identical to the GxB_* versions above. + GrB_MIN_MONOID_INT8, + GrB_MIN_MONOID_INT16, + GrB_MIN_MONOID_INT32, + GrB_MIN_MONOID_INT64, + GrB_MIN_MONOID_UINT8, + GrB_MIN_MONOID_UINT16, + GrB_MIN_MONOID_UINT32, + GrB_MIN_MONOID_UINT64, + GrB_MIN_MONOID_FP32, + GrB_MIN_MONOID_FP64, + + //-------------------------------------------------------------------------- + // 10 MAX monoids: + //-------------------------------------------------------------------------- + GxB_MAX_INT8_MONOID, // identity: INT8_MIN terminal: INT8_MAX GxB_MAX_INT16_MONOID, // identity: INT16_MIN terminal: INT16_MAX GxB_MAX_INT32_MONOID, // identity: INT32_MIN terminal: INT32_MAX @@ -5998,7 +7313,22 @@ GB_PUBLIC GrB_Monoid GxB_MAX_FP32_MONOID, // identity: -INFINITY terminal: INFINITY GxB_MAX_FP64_MONOID, // identity: -INFINITY terminal: INFINITY - // PLUS monoids: + // identical monoids now in the v1.3 spec: + GrB_MAX_MONOID_INT8, + GrB_MAX_MONOID_INT16, + GrB_MAX_MONOID_INT32, + GrB_MAX_MONOID_INT64, + GrB_MAX_MONOID_UINT8, + GrB_MAX_MONOID_UINT16, + GrB_MAX_MONOID_UINT32, + GrB_MAX_MONOID_UINT64, + GrB_MAX_MONOID_FP32, + GrB_MAX_MONOID_FP64, + + //-------------------------------------------------------------------------- + // 12 PLUS monoids: + //-------------------------------------------------------------------------- + GxB_PLUS_INT8_MONOID, // identity: 0 terminal: none GxB_PLUS_INT16_MONOID, // identity: 0 terminal: none GxB_PLUS_INT32_MONOID, // identity: 0 terminal: none @@ -6009,8 +7339,27 @@ GB_PUBLIC GrB_Monoid GxB_PLUS_UINT64_MONOID, // identity: 0 terminal: none GxB_PLUS_FP32_MONOID, // identity: 0 terminal: none GxB_PLUS_FP64_MONOID, // identity: 0 terminal: none + GxB_PLUS_FC32_MONOID, // identity: 0 terminal: none + GxB_PLUS_FC64_MONOID, // identity: 0 terminal: none + + // identical monoids now in the v1.3 spec: note the complex monoids + // do not appear in the v1.3 spec. They are SuiteSparse:GraphBLAS + // extensions only. + GrB_PLUS_MONOID_INT8, + GrB_PLUS_MONOID_INT16, + GrB_PLUS_MONOID_INT32, + GrB_PLUS_MONOID_INT64, + GrB_PLUS_MONOID_UINT8, + GrB_PLUS_MONOID_UINT16, + GrB_PLUS_MONOID_UINT32, + GrB_PLUS_MONOID_UINT64, + GrB_PLUS_MONOID_FP32, + GrB_PLUS_MONOID_FP64, + + //-------------------------------------------------------------------------- + // 12 TIMES monoids: + //-------------------------------------------------------------------------- - // TIMES monoids: GxB_TIMES_INT8_MONOID, // identity: 1 terminal: 0 GxB_TIMES_INT16_MONOID, // identity: 1 terminal: 0 GxB_TIMES_INT32_MONOID, // identity: 1 terminal: 0 @@ -6021,8 +7370,30 @@ GB_PUBLIC GrB_Monoid GxB_TIMES_UINT64_MONOID, // identity: 1 terminal: 0 GxB_TIMES_FP32_MONOID, // identity: 1 terminal: none GxB_TIMES_FP64_MONOID, // identity: 1 terminal: none + GxB_TIMES_FC32_MONOID, // identity: 1 terminal: none + GxB_TIMES_FC64_MONOID, // identity: 1 terminal: none + + // identical monoids now in the v1.3 spec: note the complex monoids + // do not appear in the v1.3 spec. They are SuiteSparse:GraphBLAS + // extensions only. + GrB_TIMES_MONOID_INT8, + GrB_TIMES_MONOID_INT16, + GrB_TIMES_MONOID_INT32, + GrB_TIMES_MONOID_INT64, + GrB_TIMES_MONOID_UINT8, + GrB_TIMES_MONOID_UINT16, + GrB_TIMES_MONOID_UINT32, + GrB_TIMES_MONOID_UINT64, + GrB_TIMES_MONOID_FP32, + GrB_TIMES_MONOID_FP64, + + //-------------------------------------------------------------------------- + // 12 ANY monoids: (excluding boolean, listed below) + //-------------------------------------------------------------------------- + + // These do not appear in the v1.3 C API of the GraphBLAS Specification, + // since the ANY operator is a SuiteSparse:GraphBLAS extension. - // ANY monoids: GxB_ANY_INT8_MONOID, // identity: any value terminal: any value GxB_ANY_INT16_MONOID, // identity: any value terminal: any value GxB_ANY_INT32_MONOID, // identity: any value terminal: any value @@ -6033,46 +7404,112 @@ GB_PUBLIC GrB_Monoid GxB_ANY_UINT64_MONOID, // identity: any value terminal: any value GxB_ANY_FP32_MONOID, // identity: any value terminal: any value GxB_ANY_FP64_MONOID, // identity: any value terminal: any value + GxB_ANY_FC32_MONOID, // identity: any value terminal: any value + GxB_ANY_FC64_MONOID, // identity: any value terminal: any value + + //-------------------------------------------------------------------------- + // 5 Boolean monoids: + //-------------------------------------------------------------------------- - // Boolean monoids: GxB_ANY_BOOL_MONOID, // identity: any value terminal: any value GxB_LOR_BOOL_MONOID, // identity: false terminal: true GxB_LAND_BOOL_MONOID, // identity: true terminal: false GxB_LXOR_BOOL_MONOID, // identity: false - GxB_EQ_BOOL_MONOID ; // identity: true + GxB_LXNOR_BOOL_MONOID, // identity: true + GxB_EQ_BOOL_MONOID, // identity: true (same as LXNOR monoid) + + // the LOR, LAND, LXOR, and LXNOR monoids now appear in the v1.3 C API: + GrB_LOR_MONOID_BOOL, + GrB_LAND_MONOID_BOOL, + GrB_LXOR_MONOID_BOOL, + GrB_LXNOR_MONOID_BOOL, + + //-------------------------------------------------------------------------- + // 16 Bitwise-or monoids: + //-------------------------------------------------------------------------- + + // The v1.3 specification adds the bitwise operators, but no predefined + // monoids or semirings that use them. + + // BOR monoids (bitwise or): + GxB_BOR_UINT8_MONOID, // identity: 0 terminal: 0xFF + GxB_BOR_UINT16_MONOID, // identity: 0 terminal: 0xFFFF + GxB_BOR_UINT32_MONOID, // identity: 0 terminal: 0xFFFFFFFF + GxB_BOR_UINT64_MONOID, // identity: 0 terminal: 0xFFFFFFFFFFFFFFFF + + // BAND monoids (bitwise and): + GxB_BAND_UINT8_MONOID, // identity: 0xFF terminal: 0 + GxB_BAND_UINT16_MONOID, // identity: 0xFFFF terminal: 0 + GxB_BAND_UINT32_MONOID, // identity: 0xFFFFFFFF terminal: 0 + GxB_BAND_UINT64_MONOID, // identity: 0xFFFFFFFFFFFFFFFF terminal: 0 + + // BXOR monoids (bitwise xor): + GxB_BXOR_UINT8_MONOID, // identity: 0 + GxB_BXOR_UINT16_MONOID, // identity: 0 + GxB_BXOR_UINT32_MONOID, // identity: 0 + GxB_BXOR_UINT64_MONOID, // identity: 0 + + // BXNOR monoids (bitwise xnor): + GxB_BXNOR_UINT8_MONOID, // identity: 0xFF + GxB_BXNOR_UINT16_MONOID, // identity: 0xFFFF + GxB_BXNOR_UINT32_MONOID, // identity: 0xFFFFFFFF + GxB_BXNOR_UINT64_MONOID ; // identity: 0xFFFFFFFFFFFFFFFF //------------------------------------------------------------------------------ // built-in semirings //------------------------------------------------------------------------------ -// Using built-in types and operators, 1355 unique semirings can be built. -// This count excludes redundant semirings (for example GxB_TIMES_BOOL and -// GxB_LAND_BOOL are different operators but they are redundant since they -// always return the same result). +// Using built-in types and operators, SuiteSparse:GraphBLAS provides +// 1473 pre-defined, built-in semirings: // 1000 semirings with a multiply operator TxT -> T where T is non-Boolean, // from the complete cross product of: -// 5 add monoids: MIN, MAX, PLUS, TIMES, ANY +// 5 monoids: MIN, MAX, PLUS, TIMES, ANY // 20 multiply operators: -// FIRST, SECOND, MIN, MAX, PLUS, MINUS, RMINUS, TIMES, DIV, RDIV, -// ISEQ, ISNE, ISGT, ISLT, ISGE, ISLE, -// LOR, LAND, LXOR -// 10 non-Boolean types, T +// FIRST, SECOND, PAIR, MIN, MAX, PLUS, MINUS, TIMES, DIV, RDIV, RMINUS +// ISEQ, ISNE, ISGT, ISLT, ISGE, ISLE, +// LOR, LAND, LXOR +// 10 non-Boolean real types, T +// +// Note that min_pair, max_pair, times_pair are all identical to any_pair. +// These 30 semirings are named below, but are internally remapped to +// their corresponding any_pair semiring. // 300 semirings with a comparison operator TxT -> bool, where T is // non-Boolean, from the complete cross product of: -// 5 Boolean add monoids: LAND, LOR, LXOR, EQ, ANY +// 5 Boolean monoids: LAND, LOR, LXOR, EQ, ANY // 6 multiply operators: EQ, NE, GT, LT, GE, LE -// 10 non-Boolean types, T +// 10 non-Boolean real types, T // 55 semirings with purely Boolean types, bool x bool -> bool, from the // complete cross product of: -// 5 Boolean add monoids LAND, LOR, LXOR, EQ, ANY +// 5 Boolean monoids LAND, LOR, LXOR, EQ, ANY // 11 multiply operators: // FIRST, SECOND, LOR, LAND, LXOR, EQ, GT, LT, GE, LE, PAIR +// +// Note that lor_pair, land_pair, and eq_pair are all identical to any_pair. +// These 3 semirings are named below, but are internally remapped to +// any_pair_bool semiring. + +// 54 complex semirings: TxT -> T where T is float complex or double complex: + +// 3 complex monoids: PLUS, TIMES, ANY +// 9 complex multiply operators: +// FIRST, SECOND, PAIR, PLUS, MINUS, TIMES, DIV, RDIV, RMINUS +// 2 complex types +// +// Note that times_pair is identical to any_pair. +// These 2 semirings are named below, but are internally remapped to +// their corresponding any_pair semiring. + +// 64 bitwise semirings: TxT -> T where T is an unsigned integer: + +// 4 bitwise monoids: BOR, BAND, BXOR, BXNOR +// 4 bitwise multiply operators: BOR, BAND, BXOR, BXNOR +// 4 unsigned integer types: UINT8, UINT16, UINT32, UINT64 // The ANY operator is also valid to use as a multiplicative operator in a // semiring, but serves no purpose in that case. The ANY operator is meant as @@ -6080,6 +7517,12 @@ GB_PUBLIC GrB_Monoid // as soon as any value is found. A valid user semiring can be constructed // with ANY as the multiply operator, but they are not predefined below. +// Likewise, additional built-in operators can be used as multiplicative +// operators for floating-point semirings (POW, ATAN2, HYPOT, ...) and many +// more semirings can be constructed from bitwise monoids and many integer +// binary (non-bitwise) multiplicative operators, but these are not +// pre-defined. + // In the names below, each semiring has a name of the form GxB_add_mult_T // where add is the additive monoid, mult is the multiply operator, and T is // the type. The type T is always the type of x and y for the z=mult(x,y) @@ -6087,6 +7530,12 @@ GB_PUBLIC GrB_Monoid // always the same. This is the type T for the first set, and Boolean for // the second and third sets of semirngs. +// 1473 = 1000 + 300 + 55 + 54 + 64 semirings are named below, but 35 = 30 + 3 +// + 2 are identical to the corresponding any_pair semirings of the same type. +// There are thus 1438 unique semirings listed below. The PAIR multiplier thus +// appears in 26 unique semirings: 13 any_pair (one per 13 types), 12 plus_pair +// (for all but bool), and lxor_pair for bool. + GB_PUBLIC GrB_Semiring //------------------------------------------------------------------------------ @@ -6094,345 +7543,628 @@ GB_PUBLIC GrB_Semiring //------------------------------------------------------------------------------ // semirings with multiply op: z = FIRST (x,y), all types x,y,z the same: - GxB_MIN_FIRST_INT8 , GxB_MAX_FIRST_INT8 , GxB_PLUS_FIRST_INT8 , GxB_TIMES_FIRST_INT8 , GxB_ANY_FIRST_INT8 , - GxB_MIN_FIRST_UINT8 , GxB_MAX_FIRST_UINT8 , GxB_PLUS_FIRST_UINT8 , GxB_TIMES_FIRST_UINT8 , GxB_ANY_FIRST_UINT8 , - GxB_MIN_FIRST_INT16 , GxB_MAX_FIRST_INT16 , GxB_PLUS_FIRST_INT16 , GxB_TIMES_FIRST_INT16 , GxB_ANY_FIRST_INT16 , - GxB_MIN_FIRST_UINT16 , GxB_MAX_FIRST_UINT16 , GxB_PLUS_FIRST_UINT16 , GxB_TIMES_FIRST_UINT16 , GxB_ANY_FIRST_UINT16 , - GxB_MIN_FIRST_INT32 , GxB_MAX_FIRST_INT32 , GxB_PLUS_FIRST_INT32 , GxB_TIMES_FIRST_INT32 , GxB_ANY_FIRST_INT32 , - GxB_MIN_FIRST_UINT32 , GxB_MAX_FIRST_UINT32 , GxB_PLUS_FIRST_UINT32 , GxB_TIMES_FIRST_UINT32 , GxB_ANY_FIRST_UINT32 , - GxB_MIN_FIRST_INT64 , GxB_MAX_FIRST_INT64 , GxB_PLUS_FIRST_INT64 , GxB_TIMES_FIRST_INT64 , GxB_ANY_FIRST_INT64 , - GxB_MIN_FIRST_UINT64 , GxB_MAX_FIRST_UINT64 , GxB_PLUS_FIRST_UINT64 , GxB_TIMES_FIRST_UINT64 , GxB_ANY_FIRST_UINT64 , - GxB_MIN_FIRST_FP32 , GxB_MAX_FIRST_FP32 , GxB_PLUS_FIRST_FP32 , GxB_TIMES_FIRST_FP32 , GxB_ANY_FIRST_FP32 , - GxB_MIN_FIRST_FP64 , GxB_MAX_FIRST_FP64 , GxB_PLUS_FIRST_FP64 , GxB_TIMES_FIRST_FP64 , GxB_ANY_FIRST_FP64 , + GxB_MIN_FIRST_INT8 , GxB_MAX_FIRST_INT8 , GxB_PLUS_FIRST_INT8 , GxB_TIMES_FIRST_INT8 , GxB_ANY_FIRST_INT8 , + GxB_MIN_FIRST_INT16 , GxB_MAX_FIRST_INT16 , GxB_PLUS_FIRST_INT16 , GxB_TIMES_FIRST_INT16 , GxB_ANY_FIRST_INT16 , + GxB_MIN_FIRST_INT32 , GxB_MAX_FIRST_INT32 , GxB_PLUS_FIRST_INT32 , GxB_TIMES_FIRST_INT32 , GxB_ANY_FIRST_INT32 , + GxB_MIN_FIRST_INT64 , GxB_MAX_FIRST_INT64 , GxB_PLUS_FIRST_INT64 , GxB_TIMES_FIRST_INT64 , GxB_ANY_FIRST_INT64 , + GxB_MIN_FIRST_UINT8 , GxB_MAX_FIRST_UINT8 , GxB_PLUS_FIRST_UINT8 , GxB_TIMES_FIRST_UINT8 , GxB_ANY_FIRST_UINT8 , + GxB_MIN_FIRST_UINT16 , GxB_MAX_FIRST_UINT16 , GxB_PLUS_FIRST_UINT16 , GxB_TIMES_FIRST_UINT16 , GxB_ANY_FIRST_UINT16 , + GxB_MIN_FIRST_UINT32 , GxB_MAX_FIRST_UINT32 , GxB_PLUS_FIRST_UINT32 , GxB_TIMES_FIRST_UINT32 , GxB_ANY_FIRST_UINT32 , + GxB_MIN_FIRST_UINT64 , GxB_MAX_FIRST_UINT64 , GxB_PLUS_FIRST_UINT64 , GxB_TIMES_FIRST_UINT64 , GxB_ANY_FIRST_UINT64 , + GxB_MIN_FIRST_FP32 , GxB_MAX_FIRST_FP32 , GxB_PLUS_FIRST_FP32 , GxB_TIMES_FIRST_FP32 , GxB_ANY_FIRST_FP32 , + GxB_MIN_FIRST_FP64 , GxB_MAX_FIRST_FP64 , GxB_PLUS_FIRST_FP64 , GxB_TIMES_FIRST_FP64 , GxB_ANY_FIRST_FP64 , // semirings with multiply op: z = SECOND (x,y), all types x,y,z the same: - GxB_MIN_SECOND_INT8 , GxB_MAX_SECOND_INT8 , GxB_PLUS_SECOND_INT8 , GxB_TIMES_SECOND_INT8 , GxB_ANY_SECOND_INT8 , - GxB_MIN_SECOND_UINT8 , GxB_MAX_SECOND_UINT8 , GxB_PLUS_SECOND_UINT8 , GxB_TIMES_SECOND_UINT8 , GxB_ANY_SECOND_UINT8 , - GxB_MIN_SECOND_INT16 , GxB_MAX_SECOND_INT16 , GxB_PLUS_SECOND_INT16 , GxB_TIMES_SECOND_INT16 , GxB_ANY_SECOND_INT16 , - GxB_MIN_SECOND_UINT16 , GxB_MAX_SECOND_UINT16 , GxB_PLUS_SECOND_UINT16 , GxB_TIMES_SECOND_UINT16, GxB_ANY_SECOND_UINT16 , - GxB_MIN_SECOND_INT32 , GxB_MAX_SECOND_INT32 , GxB_PLUS_SECOND_INT32 , GxB_TIMES_SECOND_INT32 , GxB_ANY_SECOND_INT32 , - GxB_MIN_SECOND_UINT32 , GxB_MAX_SECOND_UINT32 , GxB_PLUS_SECOND_UINT32 , GxB_TIMES_SECOND_UINT32, GxB_ANY_SECOND_UINT32 , - GxB_MIN_SECOND_INT64 , GxB_MAX_SECOND_INT64 , GxB_PLUS_SECOND_INT64 , GxB_TIMES_SECOND_INT64 , GxB_ANY_SECOND_INT64 , - GxB_MIN_SECOND_UINT64 , GxB_MAX_SECOND_UINT64 , GxB_PLUS_SECOND_UINT64 , GxB_TIMES_SECOND_UINT64, GxB_ANY_SECOND_UINT64 , - GxB_MIN_SECOND_FP32 , GxB_MAX_SECOND_FP32 , GxB_PLUS_SECOND_FP32 , GxB_TIMES_SECOND_FP32 , GxB_ANY_SECOND_FP32 , - GxB_MIN_SECOND_FP64 , GxB_MAX_SECOND_FP64 , GxB_PLUS_SECOND_FP64 , GxB_TIMES_SECOND_FP64 , GxB_ANY_SECOND_FP64 , + GxB_MIN_SECOND_INT8 , GxB_MAX_SECOND_INT8 , GxB_PLUS_SECOND_INT8 , GxB_TIMES_SECOND_INT8 , GxB_ANY_SECOND_INT8 , + GxB_MIN_SECOND_INT16 , GxB_MAX_SECOND_INT16 , GxB_PLUS_SECOND_INT16 , GxB_TIMES_SECOND_INT16 , GxB_ANY_SECOND_INT16 , + GxB_MIN_SECOND_INT32 , GxB_MAX_SECOND_INT32 , GxB_PLUS_SECOND_INT32 , GxB_TIMES_SECOND_INT32 , GxB_ANY_SECOND_INT32 , + GxB_MIN_SECOND_INT64 , GxB_MAX_SECOND_INT64 , GxB_PLUS_SECOND_INT64 , GxB_TIMES_SECOND_INT64 , GxB_ANY_SECOND_INT64 , + GxB_MIN_SECOND_UINT8 , GxB_MAX_SECOND_UINT8 , GxB_PLUS_SECOND_UINT8 , GxB_TIMES_SECOND_UINT8 , GxB_ANY_SECOND_UINT8 , + GxB_MIN_SECOND_UINT16 , GxB_MAX_SECOND_UINT16 , GxB_PLUS_SECOND_UINT16 , GxB_TIMES_SECOND_UINT16, GxB_ANY_SECOND_UINT16 , + GxB_MIN_SECOND_UINT32 , GxB_MAX_SECOND_UINT32 , GxB_PLUS_SECOND_UINT32 , GxB_TIMES_SECOND_UINT32, GxB_ANY_SECOND_UINT32 , + GxB_MIN_SECOND_UINT64 , GxB_MAX_SECOND_UINT64 , GxB_PLUS_SECOND_UINT64 , GxB_TIMES_SECOND_UINT64, GxB_ANY_SECOND_UINT64 , + GxB_MIN_SECOND_FP32 , GxB_MAX_SECOND_FP32 , GxB_PLUS_SECOND_FP32 , GxB_TIMES_SECOND_FP32 , GxB_ANY_SECOND_FP32 , + GxB_MIN_SECOND_FP64 , GxB_MAX_SECOND_FP64 , GxB_PLUS_SECOND_FP64 , GxB_TIMES_SECOND_FP64 , GxB_ANY_SECOND_FP64 , // semirings with multiply op: z = PAIR (x,y), all types x,y,z the same: - GxB_MIN_PAIR_INT8 , GxB_MAX_PAIR_INT8 , GxB_PLUS_PAIR_INT8 , GxB_TIMES_PAIR_INT8 , GxB_ANY_PAIR_INT8 , - GxB_MIN_PAIR_UINT8 , GxB_MAX_PAIR_UINT8 , GxB_PLUS_PAIR_UINT8 , GxB_TIMES_PAIR_UINT8 , GxB_ANY_PAIR_UINT8 , - GxB_MIN_PAIR_INT16 , GxB_MAX_PAIR_INT16 , GxB_PLUS_PAIR_INT16 , GxB_TIMES_PAIR_INT16 , GxB_ANY_PAIR_INT16 , - GxB_MIN_PAIR_UINT16 , GxB_MAX_PAIR_UINT16 , GxB_PLUS_PAIR_UINT16 , GxB_TIMES_PAIR_UINT16 , GxB_ANY_PAIR_UINT16 , - GxB_MIN_PAIR_INT32 , GxB_MAX_PAIR_INT32 , GxB_PLUS_PAIR_INT32 , GxB_TIMES_PAIR_INT32 , GxB_ANY_PAIR_INT32 , - GxB_MIN_PAIR_UINT32 , GxB_MAX_PAIR_UINT32 , GxB_PLUS_PAIR_UINT32 , GxB_TIMES_PAIR_UINT32 , GxB_ANY_PAIR_UINT32 , - GxB_MIN_PAIR_INT64 , GxB_MAX_PAIR_INT64 , GxB_PLUS_PAIR_INT64 , GxB_TIMES_PAIR_INT64 , GxB_ANY_PAIR_INT64 , - GxB_MIN_PAIR_UINT64 , GxB_MAX_PAIR_UINT64 , GxB_PLUS_PAIR_UINT64 , GxB_TIMES_PAIR_UINT64 , GxB_ANY_PAIR_UINT64 , - GxB_MIN_PAIR_FP32 , GxB_MAX_PAIR_FP32 , GxB_PLUS_PAIR_FP32 , GxB_TIMES_PAIR_FP32 , GxB_ANY_PAIR_FP32 , - GxB_MIN_PAIR_FP64 , GxB_MAX_PAIR_FP64 , GxB_PLUS_PAIR_FP64 , GxB_TIMES_PAIR_FP64 , GxB_ANY_PAIR_FP64 , + // (note that min_pair, max_pair, times_pair are all identical to any_pair, and are marked below) + GxB_MIN_PAIR_INT8 /**/, GxB_MAX_PAIR_INT8 /**/, GxB_PLUS_PAIR_INT8 , GxB_TIMES_PAIR_INT8 /**/, GxB_ANY_PAIR_INT8 , + GxB_MIN_PAIR_INT16 /**/, GxB_MAX_PAIR_INT16 /**/, GxB_PLUS_PAIR_INT16 , GxB_TIMES_PAIR_INT16 /**/, GxB_ANY_PAIR_INT16 , + GxB_MIN_PAIR_INT32 /**/, GxB_MAX_PAIR_INT32 /**/, GxB_PLUS_PAIR_INT32 , GxB_TIMES_PAIR_INT32 /**/, GxB_ANY_PAIR_INT32 , + GxB_MIN_PAIR_INT64 /**/, GxB_MAX_PAIR_INT64 /**/, GxB_PLUS_PAIR_INT64 , GxB_TIMES_PAIR_INT64 /**/, GxB_ANY_PAIR_INT64 , + GxB_MIN_PAIR_UINT8 /**/, GxB_MAX_PAIR_UINT8 /**/, GxB_PLUS_PAIR_UINT8 , GxB_TIMES_PAIR_UINT8 /**/, GxB_ANY_PAIR_UINT8 , + GxB_MIN_PAIR_UINT16/**/, GxB_MAX_PAIR_UINT16/**/, GxB_PLUS_PAIR_UINT16 , GxB_TIMES_PAIR_UINT16/**/, GxB_ANY_PAIR_UINT16 , + GxB_MIN_PAIR_UINT32/**/, GxB_MAX_PAIR_UINT32/**/, GxB_PLUS_PAIR_UINT32 , GxB_TIMES_PAIR_UINT32/**/, GxB_ANY_PAIR_UINT32 , + GxB_MIN_PAIR_UINT64/**/, GxB_MAX_PAIR_UINT64/**/, GxB_PLUS_PAIR_UINT64 , GxB_TIMES_PAIR_UINT64/**/, GxB_ANY_PAIR_UINT64 , + GxB_MIN_PAIR_FP32 /**/, GxB_MAX_PAIR_FP32 /**/, GxB_PLUS_PAIR_FP32 , GxB_TIMES_PAIR_FP32 /**/, GxB_ANY_PAIR_FP32 , + GxB_MIN_PAIR_FP64 /**/, GxB_MAX_PAIR_FP64 /**/, GxB_PLUS_PAIR_FP64 , GxB_TIMES_PAIR_FP64 /**/, GxB_ANY_PAIR_FP64 , // semirings with multiply op: z = MIN (x,y), all types x,y,z the same: - GxB_MIN_MIN_INT8 , GxB_MAX_MIN_INT8 , GxB_PLUS_MIN_INT8 , GxB_TIMES_MIN_INT8 , GxB_ANY_MIN_INT8 , - GxB_MIN_MIN_UINT8 , GxB_MAX_MIN_UINT8 , GxB_PLUS_MIN_UINT8 , GxB_TIMES_MIN_UINT8 , GxB_ANY_MIN_UINT8 , - GxB_MIN_MIN_INT16 , GxB_MAX_MIN_INT16 , GxB_PLUS_MIN_INT16 , GxB_TIMES_MIN_INT16 , GxB_ANY_MIN_INT16 , - GxB_MIN_MIN_UINT16 , GxB_MAX_MIN_UINT16 , GxB_PLUS_MIN_UINT16 , GxB_TIMES_MIN_UINT16 , GxB_ANY_MIN_UINT16 , - GxB_MIN_MIN_INT32 , GxB_MAX_MIN_INT32 , GxB_PLUS_MIN_INT32 , GxB_TIMES_MIN_INT32 , GxB_ANY_MIN_INT32 , - GxB_MIN_MIN_UINT32 , GxB_MAX_MIN_UINT32 , GxB_PLUS_MIN_UINT32 , GxB_TIMES_MIN_UINT32 , GxB_ANY_MIN_UINT32 , - GxB_MIN_MIN_INT64 , GxB_MAX_MIN_INT64 , GxB_PLUS_MIN_INT64 , GxB_TIMES_MIN_INT64 , GxB_ANY_MIN_INT64 , - GxB_MIN_MIN_UINT64 , GxB_MAX_MIN_UINT64 , GxB_PLUS_MIN_UINT64 , GxB_TIMES_MIN_UINT64 , GxB_ANY_MIN_UINT64 , - GxB_MIN_MIN_FP32 , GxB_MAX_MIN_FP32 , GxB_PLUS_MIN_FP32 , GxB_TIMES_MIN_FP32 , GxB_ANY_MIN_FP32 , - GxB_MIN_MIN_FP64 , GxB_MAX_MIN_FP64 , GxB_PLUS_MIN_FP64 , GxB_TIMES_MIN_FP64 , GxB_ANY_MIN_FP64 , + GxB_MIN_MIN_INT8 , GxB_MAX_MIN_INT8 , GxB_PLUS_MIN_INT8 , GxB_TIMES_MIN_INT8 , GxB_ANY_MIN_INT8 , + GxB_MIN_MIN_INT16 , GxB_MAX_MIN_INT16 , GxB_PLUS_MIN_INT16 , GxB_TIMES_MIN_INT16 , GxB_ANY_MIN_INT16 , + GxB_MIN_MIN_INT32 , GxB_MAX_MIN_INT32 , GxB_PLUS_MIN_INT32 , GxB_TIMES_MIN_INT32 , GxB_ANY_MIN_INT32 , + GxB_MIN_MIN_INT64 , GxB_MAX_MIN_INT64 , GxB_PLUS_MIN_INT64 , GxB_TIMES_MIN_INT64 , GxB_ANY_MIN_INT64 , + GxB_MIN_MIN_UINT8 , GxB_MAX_MIN_UINT8 , GxB_PLUS_MIN_UINT8 , GxB_TIMES_MIN_UINT8 , GxB_ANY_MIN_UINT8 , + GxB_MIN_MIN_UINT16 , GxB_MAX_MIN_UINT16 , GxB_PLUS_MIN_UINT16 , GxB_TIMES_MIN_UINT16 , GxB_ANY_MIN_UINT16 , + GxB_MIN_MIN_UINT32 , GxB_MAX_MIN_UINT32 , GxB_PLUS_MIN_UINT32 , GxB_TIMES_MIN_UINT32 , GxB_ANY_MIN_UINT32 , + GxB_MIN_MIN_UINT64 , GxB_MAX_MIN_UINT64 , GxB_PLUS_MIN_UINT64 , GxB_TIMES_MIN_UINT64 , GxB_ANY_MIN_UINT64 , + GxB_MIN_MIN_FP32 , GxB_MAX_MIN_FP32 , GxB_PLUS_MIN_FP32 , GxB_TIMES_MIN_FP32 , GxB_ANY_MIN_FP32 , + GxB_MIN_MIN_FP64 , GxB_MAX_MIN_FP64 , GxB_PLUS_MIN_FP64 , GxB_TIMES_MIN_FP64 , GxB_ANY_MIN_FP64 , // semirings with multiply op: z = MAX (x,y), all types x,y,z the same: - GxB_MIN_MAX_INT8 , GxB_MAX_MAX_INT8 , GxB_PLUS_MAX_INT8 , GxB_TIMES_MAX_INT8 , GxB_ANY_MAX_INT8 , - GxB_MIN_MAX_UINT8 , GxB_MAX_MAX_UINT8 , GxB_PLUS_MAX_UINT8 , GxB_TIMES_MAX_UINT8 , GxB_ANY_MAX_UINT8 , - GxB_MIN_MAX_INT16 , GxB_MAX_MAX_INT16 , GxB_PLUS_MAX_INT16 , GxB_TIMES_MAX_INT16 , GxB_ANY_MAX_INT16 , - GxB_MIN_MAX_UINT16 , GxB_MAX_MAX_UINT16 , GxB_PLUS_MAX_UINT16 , GxB_TIMES_MAX_UINT16 , GxB_ANY_MAX_UINT16 , - GxB_MIN_MAX_INT32 , GxB_MAX_MAX_INT32 , GxB_PLUS_MAX_INT32 , GxB_TIMES_MAX_INT32 , GxB_ANY_MAX_INT32 , - GxB_MIN_MAX_UINT32 , GxB_MAX_MAX_UINT32 , GxB_PLUS_MAX_UINT32 , GxB_TIMES_MAX_UINT32 , GxB_ANY_MAX_UINT32 , - GxB_MIN_MAX_INT64 , GxB_MAX_MAX_INT64 , GxB_PLUS_MAX_INT64 , GxB_TIMES_MAX_INT64 , GxB_ANY_MAX_INT64 , - GxB_MIN_MAX_UINT64 , GxB_MAX_MAX_UINT64 , GxB_PLUS_MAX_UINT64 , GxB_TIMES_MAX_UINT64 , GxB_ANY_MAX_UINT64 , - GxB_MIN_MAX_FP32 , GxB_MAX_MAX_FP32 , GxB_PLUS_MAX_FP32 , GxB_TIMES_MAX_FP32 , GxB_ANY_MAX_FP32 , - GxB_MIN_MAX_FP64 , GxB_MAX_MAX_FP64 , GxB_PLUS_MAX_FP64 , GxB_TIMES_MAX_FP64 , GxB_ANY_MAX_FP64 , + GxB_MIN_MAX_INT8 , GxB_MAX_MAX_INT8 , GxB_PLUS_MAX_INT8 , GxB_TIMES_MAX_INT8 , GxB_ANY_MAX_INT8 , + GxB_MIN_MAX_INT16 , GxB_MAX_MAX_INT16 , GxB_PLUS_MAX_INT16 , GxB_TIMES_MAX_INT16 , GxB_ANY_MAX_INT16 , + GxB_MIN_MAX_INT32 , GxB_MAX_MAX_INT32 , GxB_PLUS_MAX_INT32 , GxB_TIMES_MAX_INT32 , GxB_ANY_MAX_INT32 , + GxB_MIN_MAX_INT64 , GxB_MAX_MAX_INT64 , GxB_PLUS_MAX_INT64 , GxB_TIMES_MAX_INT64 , GxB_ANY_MAX_INT64 , + GxB_MIN_MAX_UINT8 , GxB_MAX_MAX_UINT8 , GxB_PLUS_MAX_UINT8 , GxB_TIMES_MAX_UINT8 , GxB_ANY_MAX_UINT8 , + GxB_MIN_MAX_UINT16 , GxB_MAX_MAX_UINT16 , GxB_PLUS_MAX_UINT16 , GxB_TIMES_MAX_UINT16 , GxB_ANY_MAX_UINT16 , + GxB_MIN_MAX_UINT32 , GxB_MAX_MAX_UINT32 , GxB_PLUS_MAX_UINT32 , GxB_TIMES_MAX_UINT32 , GxB_ANY_MAX_UINT32 , + GxB_MIN_MAX_UINT64 , GxB_MAX_MAX_UINT64 , GxB_PLUS_MAX_UINT64 , GxB_TIMES_MAX_UINT64 , GxB_ANY_MAX_UINT64 , + GxB_MIN_MAX_FP32 , GxB_MAX_MAX_FP32 , GxB_PLUS_MAX_FP32 , GxB_TIMES_MAX_FP32 , GxB_ANY_MAX_FP32 , + GxB_MIN_MAX_FP64 , GxB_MAX_MAX_FP64 , GxB_PLUS_MAX_FP64 , GxB_TIMES_MAX_FP64 , GxB_ANY_MAX_FP64 , // semirings with multiply op: z = PLUS (x,y), all types x,y,z the same: - GxB_MIN_PLUS_INT8 , GxB_MAX_PLUS_INT8 , GxB_PLUS_PLUS_INT8 , GxB_TIMES_PLUS_INT8 , GxB_ANY_PLUS_INT8 , - GxB_MIN_PLUS_UINT8 , GxB_MAX_PLUS_UINT8 , GxB_PLUS_PLUS_UINT8 , GxB_TIMES_PLUS_UINT8 , GxB_ANY_PLUS_UINT8 , - GxB_MIN_PLUS_INT16 , GxB_MAX_PLUS_INT16 , GxB_PLUS_PLUS_INT16 , GxB_TIMES_PLUS_INT16 , GxB_ANY_PLUS_INT16 , - GxB_MIN_PLUS_UINT16 , GxB_MAX_PLUS_UINT16 , GxB_PLUS_PLUS_UINT16 , GxB_TIMES_PLUS_UINT16 , GxB_ANY_PLUS_UINT16 , - GxB_MIN_PLUS_INT32 , GxB_MAX_PLUS_INT32 , GxB_PLUS_PLUS_INT32 , GxB_TIMES_PLUS_INT32 , GxB_ANY_PLUS_INT32 , - GxB_MIN_PLUS_UINT32 , GxB_MAX_PLUS_UINT32 , GxB_PLUS_PLUS_UINT32 , GxB_TIMES_PLUS_UINT32 , GxB_ANY_PLUS_UINT32 , - GxB_MIN_PLUS_INT64 , GxB_MAX_PLUS_INT64 , GxB_PLUS_PLUS_INT64 , GxB_TIMES_PLUS_INT64 , GxB_ANY_PLUS_INT64 , - GxB_MIN_PLUS_UINT64 , GxB_MAX_PLUS_UINT64 , GxB_PLUS_PLUS_UINT64 , GxB_TIMES_PLUS_UINT64 , GxB_ANY_PLUS_UINT64 , - GxB_MIN_PLUS_FP32 , GxB_MAX_PLUS_FP32 , GxB_PLUS_PLUS_FP32 , GxB_TIMES_PLUS_FP32 , GxB_ANY_PLUS_FP32 , - GxB_MIN_PLUS_FP64 , GxB_MAX_PLUS_FP64 , GxB_PLUS_PLUS_FP64 , GxB_TIMES_PLUS_FP64 , GxB_ANY_PLUS_FP64 , + GxB_MIN_PLUS_INT8 , GxB_MAX_PLUS_INT8 , GxB_PLUS_PLUS_INT8 , GxB_TIMES_PLUS_INT8 , GxB_ANY_PLUS_INT8 , + GxB_MIN_PLUS_INT16 , GxB_MAX_PLUS_INT16 , GxB_PLUS_PLUS_INT16 , GxB_TIMES_PLUS_INT16 , GxB_ANY_PLUS_INT16 , + GxB_MIN_PLUS_INT32 , GxB_MAX_PLUS_INT32 , GxB_PLUS_PLUS_INT32 , GxB_TIMES_PLUS_INT32 , GxB_ANY_PLUS_INT32 , + GxB_MIN_PLUS_INT64 , GxB_MAX_PLUS_INT64 , GxB_PLUS_PLUS_INT64 , GxB_TIMES_PLUS_INT64 , GxB_ANY_PLUS_INT64 , + GxB_MIN_PLUS_UINT8 , GxB_MAX_PLUS_UINT8 , GxB_PLUS_PLUS_UINT8 , GxB_TIMES_PLUS_UINT8 , GxB_ANY_PLUS_UINT8 , + GxB_MIN_PLUS_UINT16 , GxB_MAX_PLUS_UINT16 , GxB_PLUS_PLUS_UINT16 , GxB_TIMES_PLUS_UINT16 , GxB_ANY_PLUS_UINT16 , + GxB_MIN_PLUS_UINT32 , GxB_MAX_PLUS_UINT32 , GxB_PLUS_PLUS_UINT32 , GxB_TIMES_PLUS_UINT32 , GxB_ANY_PLUS_UINT32 , + GxB_MIN_PLUS_UINT64 , GxB_MAX_PLUS_UINT64 , GxB_PLUS_PLUS_UINT64 , GxB_TIMES_PLUS_UINT64 , GxB_ANY_PLUS_UINT64 , + GxB_MIN_PLUS_FP32 , GxB_MAX_PLUS_FP32 , GxB_PLUS_PLUS_FP32 , GxB_TIMES_PLUS_FP32 , GxB_ANY_PLUS_FP32 , + GxB_MIN_PLUS_FP64 , GxB_MAX_PLUS_FP64 , GxB_PLUS_PLUS_FP64 , GxB_TIMES_PLUS_FP64 , GxB_ANY_PLUS_FP64 , // semirings with multiply op: z = MINUS (x,y), all types x,y,z the same: - GxB_MIN_MINUS_INT8 , GxB_MAX_MINUS_INT8 , GxB_PLUS_MINUS_INT8 , GxB_TIMES_MINUS_INT8 , GxB_ANY_MINUS_INT8 , - GxB_MIN_MINUS_UINT8 , GxB_MAX_MINUS_UINT8 , GxB_PLUS_MINUS_UINT8 , GxB_TIMES_MINUS_UINT8 , GxB_ANY_MINUS_UINT8 , - GxB_MIN_MINUS_INT16 , GxB_MAX_MINUS_INT16 , GxB_PLUS_MINUS_INT16 , GxB_TIMES_MINUS_INT16 , GxB_ANY_MINUS_INT16 , - GxB_MIN_MINUS_UINT16 , GxB_MAX_MINUS_UINT16 , GxB_PLUS_MINUS_UINT16 , GxB_TIMES_MINUS_UINT16 , GxB_ANY_MINUS_UINT16 , - GxB_MIN_MINUS_INT32 , GxB_MAX_MINUS_INT32 , GxB_PLUS_MINUS_INT32 , GxB_TIMES_MINUS_INT32 , GxB_ANY_MINUS_INT32 , - GxB_MIN_MINUS_UINT32 , GxB_MAX_MINUS_UINT32 , GxB_PLUS_MINUS_UINT32 , GxB_TIMES_MINUS_UINT32 , GxB_ANY_MINUS_UINT32 , - GxB_MIN_MINUS_INT64 , GxB_MAX_MINUS_INT64 , GxB_PLUS_MINUS_INT64 , GxB_TIMES_MINUS_INT64 , GxB_ANY_MINUS_INT64 , - GxB_MIN_MINUS_UINT64 , GxB_MAX_MINUS_UINT64 , GxB_PLUS_MINUS_UINT64 , GxB_TIMES_MINUS_UINT64 , GxB_ANY_MINUS_UINT64 , - GxB_MIN_MINUS_FP32 , GxB_MAX_MINUS_FP32 , GxB_PLUS_MINUS_FP32 , GxB_TIMES_MINUS_FP32 , GxB_ANY_MINUS_FP32 , - GxB_MIN_MINUS_FP64 , GxB_MAX_MINUS_FP64 , GxB_PLUS_MINUS_FP64 , GxB_TIMES_MINUS_FP64 , GxB_ANY_MINUS_FP64 , + GxB_MIN_MINUS_INT8 , GxB_MAX_MINUS_INT8 , GxB_PLUS_MINUS_INT8 , GxB_TIMES_MINUS_INT8 , GxB_ANY_MINUS_INT8 , + GxB_MIN_MINUS_INT16 , GxB_MAX_MINUS_INT16 , GxB_PLUS_MINUS_INT16 , GxB_TIMES_MINUS_INT16 , GxB_ANY_MINUS_INT16 , + GxB_MIN_MINUS_INT32 , GxB_MAX_MINUS_INT32 , GxB_PLUS_MINUS_INT32 , GxB_TIMES_MINUS_INT32 , GxB_ANY_MINUS_INT32 , + GxB_MIN_MINUS_INT64 , GxB_MAX_MINUS_INT64 , GxB_PLUS_MINUS_INT64 , GxB_TIMES_MINUS_INT64 , GxB_ANY_MINUS_INT64 , + GxB_MIN_MINUS_UINT8 , GxB_MAX_MINUS_UINT8 , GxB_PLUS_MINUS_UINT8 , GxB_TIMES_MINUS_UINT8 , GxB_ANY_MINUS_UINT8 , + GxB_MIN_MINUS_UINT16 , GxB_MAX_MINUS_UINT16 , GxB_PLUS_MINUS_UINT16 , GxB_TIMES_MINUS_UINT16 , GxB_ANY_MINUS_UINT16 , + GxB_MIN_MINUS_UINT32 , GxB_MAX_MINUS_UINT32 , GxB_PLUS_MINUS_UINT32 , GxB_TIMES_MINUS_UINT32 , GxB_ANY_MINUS_UINT32 , + GxB_MIN_MINUS_UINT64 , GxB_MAX_MINUS_UINT64 , GxB_PLUS_MINUS_UINT64 , GxB_TIMES_MINUS_UINT64 , GxB_ANY_MINUS_UINT64 , + GxB_MIN_MINUS_FP32 , GxB_MAX_MINUS_FP32 , GxB_PLUS_MINUS_FP32 , GxB_TIMES_MINUS_FP32 , GxB_ANY_MINUS_FP32 , + GxB_MIN_MINUS_FP64 , GxB_MAX_MINUS_FP64 , GxB_PLUS_MINUS_FP64 , GxB_TIMES_MINUS_FP64 , GxB_ANY_MINUS_FP64 , // semirings with multiply op: z = TIMES (x,y), all types x,y,z the same: - GxB_MIN_TIMES_INT8 , GxB_MAX_TIMES_INT8 , GxB_PLUS_TIMES_INT8 , GxB_TIMES_TIMES_INT8 , GxB_ANY_TIMES_INT8 , - GxB_MIN_TIMES_UINT8 , GxB_MAX_TIMES_UINT8 , GxB_PLUS_TIMES_UINT8 , GxB_TIMES_TIMES_UINT8 , GxB_ANY_TIMES_UINT8 , - GxB_MIN_TIMES_INT16 , GxB_MAX_TIMES_INT16 , GxB_PLUS_TIMES_INT16 , GxB_TIMES_TIMES_INT16 , GxB_ANY_TIMES_INT16 , - GxB_MIN_TIMES_UINT16 , GxB_MAX_TIMES_UINT16 , GxB_PLUS_TIMES_UINT16 , GxB_TIMES_TIMES_UINT16 , GxB_ANY_TIMES_UINT16 , - GxB_MIN_TIMES_INT32 , GxB_MAX_TIMES_INT32 , GxB_PLUS_TIMES_INT32 , GxB_TIMES_TIMES_INT32 , GxB_ANY_TIMES_INT32 , - GxB_MIN_TIMES_UINT32 , GxB_MAX_TIMES_UINT32 , GxB_PLUS_TIMES_UINT32 , GxB_TIMES_TIMES_UINT32 , GxB_ANY_TIMES_UINT32 , - GxB_MIN_TIMES_INT64 , GxB_MAX_TIMES_INT64 , GxB_PLUS_TIMES_INT64 , GxB_TIMES_TIMES_INT64 , GxB_ANY_TIMES_INT64 , - GxB_MIN_TIMES_UINT64 , GxB_MAX_TIMES_UINT64 , GxB_PLUS_TIMES_UINT64 , GxB_TIMES_TIMES_UINT64 , GxB_ANY_TIMES_UINT64 , - GxB_MIN_TIMES_FP32 , GxB_MAX_TIMES_FP32 , GxB_PLUS_TIMES_FP32 , GxB_TIMES_TIMES_FP32 , GxB_ANY_TIMES_FP32 , - GxB_MIN_TIMES_FP64 , GxB_MAX_TIMES_FP64 , GxB_PLUS_TIMES_FP64 , GxB_TIMES_TIMES_FP64 , GxB_ANY_TIMES_FP64 , + GxB_MIN_TIMES_INT8 , GxB_MAX_TIMES_INT8 , GxB_PLUS_TIMES_INT8 , GxB_TIMES_TIMES_INT8 , GxB_ANY_TIMES_INT8 , + GxB_MIN_TIMES_INT16 , GxB_MAX_TIMES_INT16 , GxB_PLUS_TIMES_INT16 , GxB_TIMES_TIMES_INT16 , GxB_ANY_TIMES_INT16 , + GxB_MIN_TIMES_INT32 , GxB_MAX_TIMES_INT32 , GxB_PLUS_TIMES_INT32 , GxB_TIMES_TIMES_INT32 , GxB_ANY_TIMES_INT32 , + GxB_MIN_TIMES_INT64 , GxB_MAX_TIMES_INT64 , GxB_PLUS_TIMES_INT64 , GxB_TIMES_TIMES_INT64 , GxB_ANY_TIMES_INT64 , + GxB_MIN_TIMES_UINT8 , GxB_MAX_TIMES_UINT8 , GxB_PLUS_TIMES_UINT8 , GxB_TIMES_TIMES_UINT8 , GxB_ANY_TIMES_UINT8 , + GxB_MIN_TIMES_UINT16 , GxB_MAX_TIMES_UINT16 , GxB_PLUS_TIMES_UINT16 , GxB_TIMES_TIMES_UINT16 , GxB_ANY_TIMES_UINT16 , + GxB_MIN_TIMES_UINT32 , GxB_MAX_TIMES_UINT32 , GxB_PLUS_TIMES_UINT32 , GxB_TIMES_TIMES_UINT32 , GxB_ANY_TIMES_UINT32 , + GxB_MIN_TIMES_UINT64 , GxB_MAX_TIMES_UINT64 , GxB_PLUS_TIMES_UINT64 , GxB_TIMES_TIMES_UINT64 , GxB_ANY_TIMES_UINT64 , + GxB_MIN_TIMES_FP32 , GxB_MAX_TIMES_FP32 , GxB_PLUS_TIMES_FP32 , GxB_TIMES_TIMES_FP32 , GxB_ANY_TIMES_FP32 , + GxB_MIN_TIMES_FP64 , GxB_MAX_TIMES_FP64 , GxB_PLUS_TIMES_FP64 , GxB_TIMES_TIMES_FP64 , GxB_ANY_TIMES_FP64 , // semirings with multiply op: z = DIV (x,y), all types x,y,z the same: - GxB_MIN_DIV_INT8 , GxB_MAX_DIV_INT8 , GxB_PLUS_DIV_INT8 , GxB_TIMES_DIV_INT8 , GxB_ANY_DIV_INT8 , - GxB_MIN_DIV_UINT8 , GxB_MAX_DIV_UINT8 , GxB_PLUS_DIV_UINT8 , GxB_TIMES_DIV_UINT8 , GxB_ANY_DIV_UINT8 , - GxB_MIN_DIV_INT16 , GxB_MAX_DIV_INT16 , GxB_PLUS_DIV_INT16 , GxB_TIMES_DIV_INT16 , GxB_ANY_DIV_INT16 , - GxB_MIN_DIV_UINT16 , GxB_MAX_DIV_UINT16 , GxB_PLUS_DIV_UINT16 , GxB_TIMES_DIV_UINT16 , GxB_ANY_DIV_UINT16 , - GxB_MIN_DIV_INT32 , GxB_MAX_DIV_INT32 , GxB_PLUS_DIV_INT32 , GxB_TIMES_DIV_INT32 , GxB_ANY_DIV_INT32 , - GxB_MIN_DIV_UINT32 , GxB_MAX_DIV_UINT32 , GxB_PLUS_DIV_UINT32 , GxB_TIMES_DIV_UINT32 , GxB_ANY_DIV_UINT32 , - GxB_MIN_DIV_INT64 , GxB_MAX_DIV_INT64 , GxB_PLUS_DIV_INT64 , GxB_TIMES_DIV_INT64 , GxB_ANY_DIV_INT64 , - GxB_MIN_DIV_UINT64 , GxB_MAX_DIV_UINT64 , GxB_PLUS_DIV_UINT64 , GxB_TIMES_DIV_UINT64 , GxB_ANY_DIV_UINT64 , - GxB_MIN_DIV_FP32 , GxB_MAX_DIV_FP32 , GxB_PLUS_DIV_FP32 , GxB_TIMES_DIV_FP32 , GxB_ANY_DIV_FP32 , - GxB_MIN_DIV_FP64 , GxB_MAX_DIV_FP64 , GxB_PLUS_DIV_FP64 , GxB_TIMES_DIV_FP64 , GxB_ANY_DIV_FP64 , + GxB_MIN_DIV_INT8 , GxB_MAX_DIV_INT8 , GxB_PLUS_DIV_INT8 , GxB_TIMES_DIV_INT8 , GxB_ANY_DIV_INT8 , + GxB_MIN_DIV_INT16 , GxB_MAX_DIV_INT16 , GxB_PLUS_DIV_INT16 , GxB_TIMES_DIV_INT16 , GxB_ANY_DIV_INT16 , + GxB_MIN_DIV_INT32 , GxB_MAX_DIV_INT32 , GxB_PLUS_DIV_INT32 , GxB_TIMES_DIV_INT32 , GxB_ANY_DIV_INT32 , + GxB_MIN_DIV_INT64 , GxB_MAX_DIV_INT64 , GxB_PLUS_DIV_INT64 , GxB_TIMES_DIV_INT64 , GxB_ANY_DIV_INT64 , + GxB_MIN_DIV_UINT8 , GxB_MAX_DIV_UINT8 , GxB_PLUS_DIV_UINT8 , GxB_TIMES_DIV_UINT8 , GxB_ANY_DIV_UINT8 , + GxB_MIN_DIV_UINT16 , GxB_MAX_DIV_UINT16 , GxB_PLUS_DIV_UINT16 , GxB_TIMES_DIV_UINT16 , GxB_ANY_DIV_UINT16 , + GxB_MIN_DIV_UINT32 , GxB_MAX_DIV_UINT32 , GxB_PLUS_DIV_UINT32 , GxB_TIMES_DIV_UINT32 , GxB_ANY_DIV_UINT32 , + GxB_MIN_DIV_UINT64 , GxB_MAX_DIV_UINT64 , GxB_PLUS_DIV_UINT64 , GxB_TIMES_DIV_UINT64 , GxB_ANY_DIV_UINT64 , + GxB_MIN_DIV_FP32 , GxB_MAX_DIV_FP32 , GxB_PLUS_DIV_FP32 , GxB_TIMES_DIV_FP32 , GxB_ANY_DIV_FP32 , + GxB_MIN_DIV_FP64 , GxB_MAX_DIV_FP64 , GxB_PLUS_DIV_FP64 , GxB_TIMES_DIV_FP64 , GxB_ANY_DIV_FP64 , // semirings with multiply op: z = RDIV (x,y), all types x,y,z the same: - GxB_MIN_RDIV_INT8 , GxB_MAX_RDIV_INT8 , GxB_PLUS_RDIV_INT8 , GxB_TIMES_RDIV_INT8 , GxB_ANY_RDIV_INT8 , - GxB_MIN_RDIV_UINT8 , GxB_MAX_RDIV_UINT8 , GxB_PLUS_RDIV_UINT8 , GxB_TIMES_RDIV_UINT8 , GxB_ANY_RDIV_UINT8 , - GxB_MIN_RDIV_INT16 , GxB_MAX_RDIV_INT16 , GxB_PLUS_RDIV_INT16 , GxB_TIMES_RDIV_INT16 , GxB_ANY_RDIV_INT16 , - GxB_MIN_RDIV_UINT16 , GxB_MAX_RDIV_UINT16 , GxB_PLUS_RDIV_UINT16 , GxB_TIMES_RDIV_UINT16 , GxB_ANY_RDIV_UINT16 , - GxB_MIN_RDIV_INT32 , GxB_MAX_RDIV_INT32 , GxB_PLUS_RDIV_INT32 , GxB_TIMES_RDIV_INT32 , GxB_ANY_RDIV_INT32 , - GxB_MIN_RDIV_UINT32 , GxB_MAX_RDIV_UINT32 , GxB_PLUS_RDIV_UINT32 , GxB_TIMES_RDIV_UINT32 , GxB_ANY_RDIV_UINT32 , - GxB_MIN_RDIV_INT64 , GxB_MAX_RDIV_INT64 , GxB_PLUS_RDIV_INT64 , GxB_TIMES_RDIV_INT64 , GxB_ANY_RDIV_INT64 , - GxB_MIN_RDIV_UINT64 , GxB_MAX_RDIV_UINT64 , GxB_PLUS_RDIV_UINT64 , GxB_TIMES_RDIV_UINT64 , GxB_ANY_RDIV_UINT64 , - GxB_MIN_RDIV_FP32 , GxB_MAX_RDIV_FP32 , GxB_PLUS_RDIV_FP32 , GxB_TIMES_RDIV_FP32 , GxB_ANY_RDIV_FP32 , - GxB_MIN_RDIV_FP64 , GxB_MAX_RDIV_FP64 , GxB_PLUS_RDIV_FP64 , GxB_TIMES_RDIV_FP64 , GxB_ANY_RDIV_FP64 , + GxB_MIN_RDIV_INT8 , GxB_MAX_RDIV_INT8 , GxB_PLUS_RDIV_INT8 , GxB_TIMES_RDIV_INT8 , GxB_ANY_RDIV_INT8 , + GxB_MIN_RDIV_INT16 , GxB_MAX_RDIV_INT16 , GxB_PLUS_RDIV_INT16 , GxB_TIMES_RDIV_INT16 , GxB_ANY_RDIV_INT16 , + GxB_MIN_RDIV_INT32 , GxB_MAX_RDIV_INT32 , GxB_PLUS_RDIV_INT32 , GxB_TIMES_RDIV_INT32 , GxB_ANY_RDIV_INT32 , + GxB_MIN_RDIV_INT64 , GxB_MAX_RDIV_INT64 , GxB_PLUS_RDIV_INT64 , GxB_TIMES_RDIV_INT64 , GxB_ANY_RDIV_INT64 , + GxB_MIN_RDIV_UINT8 , GxB_MAX_RDIV_UINT8 , GxB_PLUS_RDIV_UINT8 , GxB_TIMES_RDIV_UINT8 , GxB_ANY_RDIV_UINT8 , + GxB_MIN_RDIV_UINT16 , GxB_MAX_RDIV_UINT16 , GxB_PLUS_RDIV_UINT16 , GxB_TIMES_RDIV_UINT16 , GxB_ANY_RDIV_UINT16 , + GxB_MIN_RDIV_UINT32 , GxB_MAX_RDIV_UINT32 , GxB_PLUS_RDIV_UINT32 , GxB_TIMES_RDIV_UINT32 , GxB_ANY_RDIV_UINT32 , + GxB_MIN_RDIV_UINT64 , GxB_MAX_RDIV_UINT64 , GxB_PLUS_RDIV_UINT64 , GxB_TIMES_RDIV_UINT64 , GxB_ANY_RDIV_UINT64 , + GxB_MIN_RDIV_FP32 , GxB_MAX_RDIV_FP32 , GxB_PLUS_RDIV_FP32 , GxB_TIMES_RDIV_FP32 , GxB_ANY_RDIV_FP32 , + GxB_MIN_RDIV_FP64 , GxB_MAX_RDIV_FP64 , GxB_PLUS_RDIV_FP64 , GxB_TIMES_RDIV_FP64 , GxB_ANY_RDIV_FP64 , // semirings with multiply op: z = RMINUS (x,y), all types x,y,z the same: - GxB_MIN_RMINUS_INT8 , GxB_MAX_RMINUS_INT8 , GxB_PLUS_RMINUS_INT8 , GxB_TIMES_RMINUS_INT8 , GxB_ANY_RMINUS_INT8 , - GxB_MIN_RMINUS_UINT8 , GxB_MAX_RMINUS_UINT8 , GxB_PLUS_RMINUS_UINT8 , GxB_TIMES_RMINUS_UINT8 , GxB_ANY_RMINUS_UINT8 , - GxB_MIN_RMINUS_INT16 , GxB_MAX_RMINUS_INT16 , GxB_PLUS_RMINUS_INT16 , GxB_TIMES_RMINUS_INT16 , GxB_ANY_RMINUS_INT16 , - GxB_MIN_RMINUS_UINT16 , GxB_MAX_RMINUS_UINT16 , GxB_PLUS_RMINUS_UINT16 , GxB_TIMES_RMINUS_UINT16, GxB_ANY_RMINUS_UINT16 , - GxB_MIN_RMINUS_INT32 , GxB_MAX_RMINUS_INT32 , GxB_PLUS_RMINUS_INT32 , GxB_TIMES_RMINUS_INT32 , GxB_ANY_RMINUS_INT32 , - GxB_MIN_RMINUS_UINT32 , GxB_MAX_RMINUS_UINT32 , GxB_PLUS_RMINUS_UINT32 , GxB_TIMES_RMINUS_UINT32, GxB_ANY_RMINUS_UINT32 , - GxB_MIN_RMINUS_INT64 , GxB_MAX_RMINUS_INT64 , GxB_PLUS_RMINUS_INT64 , GxB_TIMES_RMINUS_INT64 , GxB_ANY_RMINUS_INT64 , - GxB_MIN_RMINUS_UINT64 , GxB_MAX_RMINUS_UINT64 , GxB_PLUS_RMINUS_UINT64 , GxB_TIMES_RMINUS_UINT64, GxB_ANY_RMINUS_UINT64 , - GxB_MIN_RMINUS_FP32 , GxB_MAX_RMINUS_FP32 , GxB_PLUS_RMINUS_FP32 , GxB_TIMES_RMINUS_FP32 , GxB_ANY_RMINUS_FP32 , - GxB_MIN_RMINUS_FP64 , GxB_MAX_RMINUS_FP64 , GxB_PLUS_RMINUS_FP64 , GxB_TIMES_RMINUS_FP64 , GxB_ANY_RMINUS_FP64 , + GxB_MIN_RMINUS_INT8 , GxB_MAX_RMINUS_INT8 , GxB_PLUS_RMINUS_INT8 , GxB_TIMES_RMINUS_INT8 , GxB_ANY_RMINUS_INT8 , + GxB_MIN_RMINUS_INT16 , GxB_MAX_RMINUS_INT16 , GxB_PLUS_RMINUS_INT16 , GxB_TIMES_RMINUS_INT16 , GxB_ANY_RMINUS_INT16 , + GxB_MIN_RMINUS_INT32 , GxB_MAX_RMINUS_INT32 , GxB_PLUS_RMINUS_INT32 , GxB_TIMES_RMINUS_INT32 , GxB_ANY_RMINUS_INT32 , + GxB_MIN_RMINUS_INT64 , GxB_MAX_RMINUS_INT64 , GxB_PLUS_RMINUS_INT64 , GxB_TIMES_RMINUS_INT64 , GxB_ANY_RMINUS_INT64 , + GxB_MIN_RMINUS_UINT8 , GxB_MAX_RMINUS_UINT8 , GxB_PLUS_RMINUS_UINT8 , GxB_TIMES_RMINUS_UINT8 , GxB_ANY_RMINUS_UINT8 , + GxB_MIN_RMINUS_UINT16 , GxB_MAX_RMINUS_UINT16 , GxB_PLUS_RMINUS_UINT16 , GxB_TIMES_RMINUS_UINT16, GxB_ANY_RMINUS_UINT16 , + GxB_MIN_RMINUS_UINT32 , GxB_MAX_RMINUS_UINT32 , GxB_PLUS_RMINUS_UINT32 , GxB_TIMES_RMINUS_UINT32, GxB_ANY_RMINUS_UINT32 , + GxB_MIN_RMINUS_UINT64 , GxB_MAX_RMINUS_UINT64 , GxB_PLUS_RMINUS_UINT64 , GxB_TIMES_RMINUS_UINT64, GxB_ANY_RMINUS_UINT64 , + GxB_MIN_RMINUS_FP32 , GxB_MAX_RMINUS_FP32 , GxB_PLUS_RMINUS_FP32 , GxB_TIMES_RMINUS_FP32 , GxB_ANY_RMINUS_FP32 , + GxB_MIN_RMINUS_FP64 , GxB_MAX_RMINUS_FP64 , GxB_PLUS_RMINUS_FP64 , GxB_TIMES_RMINUS_FP64 , GxB_ANY_RMINUS_FP64 , // semirings with multiply op: z = ISEQ (x,y), all types x,y,z the same: - GxB_MIN_ISEQ_INT8 , GxB_MAX_ISEQ_INT8 , GxB_PLUS_ISEQ_INT8 , GxB_TIMES_ISEQ_INT8 , GxB_ANY_ISEQ_INT8 , - GxB_MIN_ISEQ_UINT8 , GxB_MAX_ISEQ_UINT8 , GxB_PLUS_ISEQ_UINT8 , GxB_TIMES_ISEQ_UINT8 , GxB_ANY_ISEQ_UINT8 , - GxB_MIN_ISEQ_INT16 , GxB_MAX_ISEQ_INT16 , GxB_PLUS_ISEQ_INT16 , GxB_TIMES_ISEQ_INT16 , GxB_ANY_ISEQ_INT16 , - GxB_MIN_ISEQ_UINT16 , GxB_MAX_ISEQ_UINT16 , GxB_PLUS_ISEQ_UINT16 , GxB_TIMES_ISEQ_UINT16 , GxB_ANY_ISEQ_UINT16 , - GxB_MIN_ISEQ_INT32 , GxB_MAX_ISEQ_INT32 , GxB_PLUS_ISEQ_INT32 , GxB_TIMES_ISEQ_INT32 , GxB_ANY_ISEQ_INT32 , - GxB_MIN_ISEQ_UINT32 , GxB_MAX_ISEQ_UINT32 , GxB_PLUS_ISEQ_UINT32 , GxB_TIMES_ISEQ_UINT32 , GxB_ANY_ISEQ_UINT32 , - GxB_MIN_ISEQ_INT64 , GxB_MAX_ISEQ_INT64 , GxB_PLUS_ISEQ_INT64 , GxB_TIMES_ISEQ_INT64 , GxB_ANY_ISEQ_INT64 , - GxB_MIN_ISEQ_UINT64 , GxB_MAX_ISEQ_UINT64 , GxB_PLUS_ISEQ_UINT64 , GxB_TIMES_ISEQ_UINT64 , GxB_ANY_ISEQ_UINT64 , - GxB_MIN_ISEQ_FP32 , GxB_MAX_ISEQ_FP32 , GxB_PLUS_ISEQ_FP32 , GxB_TIMES_ISEQ_FP32 , GxB_ANY_ISEQ_FP32 , - GxB_MIN_ISEQ_FP64 , GxB_MAX_ISEQ_FP64 , GxB_PLUS_ISEQ_FP64 , GxB_TIMES_ISEQ_FP64 , GxB_ANY_ISEQ_FP64 , + GxB_MIN_ISEQ_INT8 , GxB_MAX_ISEQ_INT8 , GxB_PLUS_ISEQ_INT8 , GxB_TIMES_ISEQ_INT8 , GxB_ANY_ISEQ_INT8 , + GxB_MIN_ISEQ_INT16 , GxB_MAX_ISEQ_INT16 , GxB_PLUS_ISEQ_INT16 , GxB_TIMES_ISEQ_INT16 , GxB_ANY_ISEQ_INT16 , + GxB_MIN_ISEQ_INT32 , GxB_MAX_ISEQ_INT32 , GxB_PLUS_ISEQ_INT32 , GxB_TIMES_ISEQ_INT32 , GxB_ANY_ISEQ_INT32 , + GxB_MIN_ISEQ_INT64 , GxB_MAX_ISEQ_INT64 , GxB_PLUS_ISEQ_INT64 , GxB_TIMES_ISEQ_INT64 , GxB_ANY_ISEQ_INT64 , + GxB_MIN_ISEQ_UINT8 , GxB_MAX_ISEQ_UINT8 , GxB_PLUS_ISEQ_UINT8 , GxB_TIMES_ISEQ_UINT8 , GxB_ANY_ISEQ_UINT8 , + GxB_MIN_ISEQ_UINT16 , GxB_MAX_ISEQ_UINT16 , GxB_PLUS_ISEQ_UINT16 , GxB_TIMES_ISEQ_UINT16 , GxB_ANY_ISEQ_UINT16 , + GxB_MIN_ISEQ_UINT32 , GxB_MAX_ISEQ_UINT32 , GxB_PLUS_ISEQ_UINT32 , GxB_TIMES_ISEQ_UINT32 , GxB_ANY_ISEQ_UINT32 , + GxB_MIN_ISEQ_UINT64 , GxB_MAX_ISEQ_UINT64 , GxB_PLUS_ISEQ_UINT64 , GxB_TIMES_ISEQ_UINT64 , GxB_ANY_ISEQ_UINT64 , + GxB_MIN_ISEQ_FP32 , GxB_MAX_ISEQ_FP32 , GxB_PLUS_ISEQ_FP32 , GxB_TIMES_ISEQ_FP32 , GxB_ANY_ISEQ_FP32 , + GxB_MIN_ISEQ_FP64 , GxB_MAX_ISEQ_FP64 , GxB_PLUS_ISEQ_FP64 , GxB_TIMES_ISEQ_FP64 , GxB_ANY_ISEQ_FP64 , // semirings with multiply op: z = ISNE (x,y), all types x,y,z the same: - GxB_MIN_ISNE_INT8 , GxB_MAX_ISNE_INT8 , GxB_PLUS_ISNE_INT8 , GxB_TIMES_ISNE_INT8 , GxB_ANY_ISNE_INT8 , - GxB_MIN_ISNE_UINT8 , GxB_MAX_ISNE_UINT8 , GxB_PLUS_ISNE_UINT8 , GxB_TIMES_ISNE_UINT8 , GxB_ANY_ISNE_UINT8 , - GxB_MIN_ISNE_INT16 , GxB_MAX_ISNE_INT16 , GxB_PLUS_ISNE_INT16 , GxB_TIMES_ISNE_INT16 , GxB_ANY_ISNE_INT16 , - GxB_MIN_ISNE_UINT16 , GxB_MAX_ISNE_UINT16 , GxB_PLUS_ISNE_UINT16 , GxB_TIMES_ISNE_UINT16 , GxB_ANY_ISNE_UINT16 , - GxB_MIN_ISNE_INT32 , GxB_MAX_ISNE_INT32 , GxB_PLUS_ISNE_INT32 , GxB_TIMES_ISNE_INT32 , GxB_ANY_ISNE_INT32 , - GxB_MIN_ISNE_UINT32 , GxB_MAX_ISNE_UINT32 , GxB_PLUS_ISNE_UINT32 , GxB_TIMES_ISNE_UINT32 , GxB_ANY_ISNE_UINT32 , - GxB_MIN_ISNE_INT64 , GxB_MAX_ISNE_INT64 , GxB_PLUS_ISNE_INT64 , GxB_TIMES_ISNE_INT64 , GxB_ANY_ISNE_INT64 , - GxB_MIN_ISNE_UINT64 , GxB_MAX_ISNE_UINT64 , GxB_PLUS_ISNE_UINT64 , GxB_TIMES_ISNE_UINT64 , GxB_ANY_ISNE_UINT64 , - GxB_MIN_ISNE_FP32 , GxB_MAX_ISNE_FP32 , GxB_PLUS_ISNE_FP32 , GxB_TIMES_ISNE_FP32 , GxB_ANY_ISNE_FP32 , - GxB_MIN_ISNE_FP64 , GxB_MAX_ISNE_FP64 , GxB_PLUS_ISNE_FP64 , GxB_TIMES_ISNE_FP64 , GxB_ANY_ISNE_FP64 , + GxB_MIN_ISNE_INT8 , GxB_MAX_ISNE_INT8 , GxB_PLUS_ISNE_INT8 , GxB_TIMES_ISNE_INT8 , GxB_ANY_ISNE_INT8 , + GxB_MIN_ISNE_INT16 , GxB_MAX_ISNE_INT16 , GxB_PLUS_ISNE_INT16 , GxB_TIMES_ISNE_INT16 , GxB_ANY_ISNE_INT16 , + GxB_MIN_ISNE_INT32 , GxB_MAX_ISNE_INT32 , GxB_PLUS_ISNE_INT32 , GxB_TIMES_ISNE_INT32 , GxB_ANY_ISNE_INT32 , + GxB_MIN_ISNE_INT64 , GxB_MAX_ISNE_INT64 , GxB_PLUS_ISNE_INT64 , GxB_TIMES_ISNE_INT64 , GxB_ANY_ISNE_INT64 , + GxB_MIN_ISNE_UINT8 , GxB_MAX_ISNE_UINT8 , GxB_PLUS_ISNE_UINT8 , GxB_TIMES_ISNE_UINT8 , GxB_ANY_ISNE_UINT8 , + GxB_MIN_ISNE_UINT16 , GxB_MAX_ISNE_UINT16 , GxB_PLUS_ISNE_UINT16 , GxB_TIMES_ISNE_UINT16 , GxB_ANY_ISNE_UINT16 , + GxB_MIN_ISNE_UINT32 , GxB_MAX_ISNE_UINT32 , GxB_PLUS_ISNE_UINT32 , GxB_TIMES_ISNE_UINT32 , GxB_ANY_ISNE_UINT32 , + GxB_MIN_ISNE_UINT64 , GxB_MAX_ISNE_UINT64 , GxB_PLUS_ISNE_UINT64 , GxB_TIMES_ISNE_UINT64 , GxB_ANY_ISNE_UINT64 , + GxB_MIN_ISNE_FP32 , GxB_MAX_ISNE_FP32 , GxB_PLUS_ISNE_FP32 , GxB_TIMES_ISNE_FP32 , GxB_ANY_ISNE_FP32 , + GxB_MIN_ISNE_FP64 , GxB_MAX_ISNE_FP64 , GxB_PLUS_ISNE_FP64 , GxB_TIMES_ISNE_FP64 , GxB_ANY_ISNE_FP64 , // semirings with multiply op: z = ISGT (x,y), all types x,y,z the same: - GxB_MIN_ISGT_INT8 , GxB_MAX_ISGT_INT8 , GxB_PLUS_ISGT_INT8 , GxB_TIMES_ISGT_INT8 , GxB_ANY_ISGT_INT8 , - GxB_MIN_ISGT_UINT8 , GxB_MAX_ISGT_UINT8 , GxB_PLUS_ISGT_UINT8 , GxB_TIMES_ISGT_UINT8 , GxB_ANY_ISGT_UINT8 , - GxB_MIN_ISGT_INT16 , GxB_MAX_ISGT_INT16 , GxB_PLUS_ISGT_INT16 , GxB_TIMES_ISGT_INT16 , GxB_ANY_ISGT_INT16 , - GxB_MIN_ISGT_UINT16 , GxB_MAX_ISGT_UINT16 , GxB_PLUS_ISGT_UINT16 , GxB_TIMES_ISGT_UINT16 , GxB_ANY_ISGT_UINT16 , - GxB_MIN_ISGT_INT32 , GxB_MAX_ISGT_INT32 , GxB_PLUS_ISGT_INT32 , GxB_TIMES_ISGT_INT32 , GxB_ANY_ISGT_INT32 , - GxB_MIN_ISGT_UINT32 , GxB_MAX_ISGT_UINT32 , GxB_PLUS_ISGT_UINT32 , GxB_TIMES_ISGT_UINT32 , GxB_ANY_ISGT_UINT32 , - GxB_MIN_ISGT_INT64 , GxB_MAX_ISGT_INT64 , GxB_PLUS_ISGT_INT64 , GxB_TIMES_ISGT_INT64 , GxB_ANY_ISGT_INT64 , - GxB_MIN_ISGT_UINT64 , GxB_MAX_ISGT_UINT64 , GxB_PLUS_ISGT_UINT64 , GxB_TIMES_ISGT_UINT64 , GxB_ANY_ISGT_UINT64 , - GxB_MIN_ISGT_FP32 , GxB_MAX_ISGT_FP32 , GxB_PLUS_ISGT_FP32 , GxB_TIMES_ISGT_FP32 , GxB_ANY_ISGT_FP32 , - GxB_MIN_ISGT_FP64 , GxB_MAX_ISGT_FP64 , GxB_PLUS_ISGT_FP64 , GxB_TIMES_ISGT_FP64 , GxB_ANY_ISGT_FP64 , + GxB_MIN_ISGT_INT8 , GxB_MAX_ISGT_INT8 , GxB_PLUS_ISGT_INT8 , GxB_TIMES_ISGT_INT8 , GxB_ANY_ISGT_INT8 , + GxB_MIN_ISGT_INT16 , GxB_MAX_ISGT_INT16 , GxB_PLUS_ISGT_INT16 , GxB_TIMES_ISGT_INT16 , GxB_ANY_ISGT_INT16 , + GxB_MIN_ISGT_INT32 , GxB_MAX_ISGT_INT32 , GxB_PLUS_ISGT_INT32 , GxB_TIMES_ISGT_INT32 , GxB_ANY_ISGT_INT32 , + GxB_MIN_ISGT_INT64 , GxB_MAX_ISGT_INT64 , GxB_PLUS_ISGT_INT64 , GxB_TIMES_ISGT_INT64 , GxB_ANY_ISGT_INT64 , + GxB_MIN_ISGT_UINT8 , GxB_MAX_ISGT_UINT8 , GxB_PLUS_ISGT_UINT8 , GxB_TIMES_ISGT_UINT8 , GxB_ANY_ISGT_UINT8 , + GxB_MIN_ISGT_UINT16 , GxB_MAX_ISGT_UINT16 , GxB_PLUS_ISGT_UINT16 , GxB_TIMES_ISGT_UINT16 , GxB_ANY_ISGT_UINT16 , + GxB_MIN_ISGT_UINT32 , GxB_MAX_ISGT_UINT32 , GxB_PLUS_ISGT_UINT32 , GxB_TIMES_ISGT_UINT32 , GxB_ANY_ISGT_UINT32 , + GxB_MIN_ISGT_UINT64 , GxB_MAX_ISGT_UINT64 , GxB_PLUS_ISGT_UINT64 , GxB_TIMES_ISGT_UINT64 , GxB_ANY_ISGT_UINT64 , + GxB_MIN_ISGT_FP32 , GxB_MAX_ISGT_FP32 , GxB_PLUS_ISGT_FP32 , GxB_TIMES_ISGT_FP32 , GxB_ANY_ISGT_FP32 , + GxB_MIN_ISGT_FP64 , GxB_MAX_ISGT_FP64 , GxB_PLUS_ISGT_FP64 , GxB_TIMES_ISGT_FP64 , GxB_ANY_ISGT_FP64 , // semirings with multiply op: z = ISLT (x,y), all types x,y,z the same: - GxB_MIN_ISLT_INT8 , GxB_MAX_ISLT_INT8 , GxB_PLUS_ISLT_INT8 , GxB_TIMES_ISLT_INT8 , GxB_ANY_ISLT_INT8 , - GxB_MIN_ISLT_UINT8 , GxB_MAX_ISLT_UINT8 , GxB_PLUS_ISLT_UINT8 , GxB_TIMES_ISLT_UINT8 , GxB_ANY_ISLT_UINT8 , - GxB_MIN_ISLT_INT16 , GxB_MAX_ISLT_INT16 , GxB_PLUS_ISLT_INT16 , GxB_TIMES_ISLT_INT16 , GxB_ANY_ISLT_INT16 , - GxB_MIN_ISLT_UINT16 , GxB_MAX_ISLT_UINT16 , GxB_PLUS_ISLT_UINT16 , GxB_TIMES_ISLT_UINT16 , GxB_ANY_ISLT_UINT16 , - GxB_MIN_ISLT_INT32 , GxB_MAX_ISLT_INT32 , GxB_PLUS_ISLT_INT32 , GxB_TIMES_ISLT_INT32 , GxB_ANY_ISLT_INT32 , - GxB_MIN_ISLT_UINT32 , GxB_MAX_ISLT_UINT32 , GxB_PLUS_ISLT_UINT32 , GxB_TIMES_ISLT_UINT32 , GxB_ANY_ISLT_UINT32 , - GxB_MIN_ISLT_INT64 , GxB_MAX_ISLT_INT64 , GxB_PLUS_ISLT_INT64 , GxB_TIMES_ISLT_INT64 , GxB_ANY_ISLT_INT64 , - GxB_MIN_ISLT_UINT64 , GxB_MAX_ISLT_UINT64 , GxB_PLUS_ISLT_UINT64 , GxB_TIMES_ISLT_UINT64 , GxB_ANY_ISLT_UINT64 , - GxB_MIN_ISLT_FP32 , GxB_MAX_ISLT_FP32 , GxB_PLUS_ISLT_FP32 , GxB_TIMES_ISLT_FP32 , GxB_ANY_ISLT_FP32 , - GxB_MIN_ISLT_FP64 , GxB_MAX_ISLT_FP64 , GxB_PLUS_ISLT_FP64 , GxB_TIMES_ISLT_FP64 , GxB_ANY_ISLT_FP64 , + GxB_MIN_ISLT_INT8 , GxB_MAX_ISLT_INT8 , GxB_PLUS_ISLT_INT8 , GxB_TIMES_ISLT_INT8 , GxB_ANY_ISLT_INT8 , + GxB_MIN_ISLT_INT16 , GxB_MAX_ISLT_INT16 , GxB_PLUS_ISLT_INT16 , GxB_TIMES_ISLT_INT16 , GxB_ANY_ISLT_INT16 , + GxB_MIN_ISLT_INT32 , GxB_MAX_ISLT_INT32 , GxB_PLUS_ISLT_INT32 , GxB_TIMES_ISLT_INT32 , GxB_ANY_ISLT_INT32 , + GxB_MIN_ISLT_INT64 , GxB_MAX_ISLT_INT64 , GxB_PLUS_ISLT_INT64 , GxB_TIMES_ISLT_INT64 , GxB_ANY_ISLT_INT64 , + GxB_MIN_ISLT_UINT8 , GxB_MAX_ISLT_UINT8 , GxB_PLUS_ISLT_UINT8 , GxB_TIMES_ISLT_UINT8 , GxB_ANY_ISLT_UINT8 , + GxB_MIN_ISLT_UINT16 , GxB_MAX_ISLT_UINT16 , GxB_PLUS_ISLT_UINT16 , GxB_TIMES_ISLT_UINT16 , GxB_ANY_ISLT_UINT16 , + GxB_MIN_ISLT_UINT32 , GxB_MAX_ISLT_UINT32 , GxB_PLUS_ISLT_UINT32 , GxB_TIMES_ISLT_UINT32 , GxB_ANY_ISLT_UINT32 , + GxB_MIN_ISLT_UINT64 , GxB_MAX_ISLT_UINT64 , GxB_PLUS_ISLT_UINT64 , GxB_TIMES_ISLT_UINT64 , GxB_ANY_ISLT_UINT64 , + GxB_MIN_ISLT_FP32 , GxB_MAX_ISLT_FP32 , GxB_PLUS_ISLT_FP32 , GxB_TIMES_ISLT_FP32 , GxB_ANY_ISLT_FP32 , + GxB_MIN_ISLT_FP64 , GxB_MAX_ISLT_FP64 , GxB_PLUS_ISLT_FP64 , GxB_TIMES_ISLT_FP64 , GxB_ANY_ISLT_FP64 , // semirings with multiply op: z = ISGE (x,y), all types x,y,z the same: - GxB_MIN_ISGE_INT8 , GxB_MAX_ISGE_INT8 , GxB_PLUS_ISGE_INT8 , GxB_TIMES_ISGE_INT8 , GxB_ANY_ISGE_INT8 , - GxB_MIN_ISGE_UINT8 , GxB_MAX_ISGE_UINT8 , GxB_PLUS_ISGE_UINT8 , GxB_TIMES_ISGE_UINT8 , GxB_ANY_ISGE_UINT8 , - GxB_MIN_ISGE_INT16 , GxB_MAX_ISGE_INT16 , GxB_PLUS_ISGE_INT16 , GxB_TIMES_ISGE_INT16 , GxB_ANY_ISGE_INT16 , - GxB_MIN_ISGE_UINT16 , GxB_MAX_ISGE_UINT16 , GxB_PLUS_ISGE_UINT16 , GxB_TIMES_ISGE_UINT16 , GxB_ANY_ISGE_UINT16 , - GxB_MIN_ISGE_INT32 , GxB_MAX_ISGE_INT32 , GxB_PLUS_ISGE_INT32 , GxB_TIMES_ISGE_INT32 , GxB_ANY_ISGE_INT32 , - GxB_MIN_ISGE_UINT32 , GxB_MAX_ISGE_UINT32 , GxB_PLUS_ISGE_UINT32 , GxB_TIMES_ISGE_UINT32 , GxB_ANY_ISGE_UINT32 , - GxB_MIN_ISGE_INT64 , GxB_MAX_ISGE_INT64 , GxB_PLUS_ISGE_INT64 , GxB_TIMES_ISGE_INT64 , GxB_ANY_ISGE_INT64 , - GxB_MIN_ISGE_UINT64 , GxB_MAX_ISGE_UINT64 , GxB_PLUS_ISGE_UINT64 , GxB_TIMES_ISGE_UINT64 , GxB_ANY_ISGE_UINT64 , - GxB_MIN_ISGE_FP32 , GxB_MAX_ISGE_FP32 , GxB_PLUS_ISGE_FP32 , GxB_TIMES_ISGE_FP32 , GxB_ANY_ISGE_FP32 , - GxB_MIN_ISGE_FP64 , GxB_MAX_ISGE_FP64 , GxB_PLUS_ISGE_FP64 , GxB_TIMES_ISGE_FP64 , GxB_ANY_ISGE_FP64 , + GxB_MIN_ISGE_INT8 , GxB_MAX_ISGE_INT8 , GxB_PLUS_ISGE_INT8 , GxB_TIMES_ISGE_INT8 , GxB_ANY_ISGE_INT8 , + GxB_MIN_ISGE_INT16 , GxB_MAX_ISGE_INT16 , GxB_PLUS_ISGE_INT16 , GxB_TIMES_ISGE_INT16 , GxB_ANY_ISGE_INT16 , + GxB_MIN_ISGE_INT32 , GxB_MAX_ISGE_INT32 , GxB_PLUS_ISGE_INT32 , GxB_TIMES_ISGE_INT32 , GxB_ANY_ISGE_INT32 , + GxB_MIN_ISGE_INT64 , GxB_MAX_ISGE_INT64 , GxB_PLUS_ISGE_INT64 , GxB_TIMES_ISGE_INT64 , GxB_ANY_ISGE_INT64 , + GxB_MIN_ISGE_UINT8 , GxB_MAX_ISGE_UINT8 , GxB_PLUS_ISGE_UINT8 , GxB_TIMES_ISGE_UINT8 , GxB_ANY_ISGE_UINT8 , + GxB_MIN_ISGE_UINT16 , GxB_MAX_ISGE_UINT16 , GxB_PLUS_ISGE_UINT16 , GxB_TIMES_ISGE_UINT16 , GxB_ANY_ISGE_UINT16 , + GxB_MIN_ISGE_UINT32 , GxB_MAX_ISGE_UINT32 , GxB_PLUS_ISGE_UINT32 , GxB_TIMES_ISGE_UINT32 , GxB_ANY_ISGE_UINT32 , + GxB_MIN_ISGE_UINT64 , GxB_MAX_ISGE_UINT64 , GxB_PLUS_ISGE_UINT64 , GxB_TIMES_ISGE_UINT64 , GxB_ANY_ISGE_UINT64 , + GxB_MIN_ISGE_FP32 , GxB_MAX_ISGE_FP32 , GxB_PLUS_ISGE_FP32 , GxB_TIMES_ISGE_FP32 , GxB_ANY_ISGE_FP32 , + GxB_MIN_ISGE_FP64 , GxB_MAX_ISGE_FP64 , GxB_PLUS_ISGE_FP64 , GxB_TIMES_ISGE_FP64 , GxB_ANY_ISGE_FP64 , // semirings with multiply op: z = ISLE (x,y), all types x,y,z the same: - GxB_MIN_ISLE_INT8 , GxB_MAX_ISLE_INT8 , GxB_PLUS_ISLE_INT8 , GxB_TIMES_ISLE_INT8 , GxB_ANY_ISLE_INT8 , - GxB_MIN_ISLE_UINT8 , GxB_MAX_ISLE_UINT8 , GxB_PLUS_ISLE_UINT8 , GxB_TIMES_ISLE_UINT8 , GxB_ANY_ISLE_UINT8 , - GxB_MIN_ISLE_INT16 , GxB_MAX_ISLE_INT16 , GxB_PLUS_ISLE_INT16 , GxB_TIMES_ISLE_INT16 , GxB_ANY_ISLE_INT16 , - GxB_MIN_ISLE_UINT16 , GxB_MAX_ISLE_UINT16 , GxB_PLUS_ISLE_UINT16 , GxB_TIMES_ISLE_UINT16 , GxB_ANY_ISLE_UINT16 , - GxB_MIN_ISLE_INT32 , GxB_MAX_ISLE_INT32 , GxB_PLUS_ISLE_INT32 , GxB_TIMES_ISLE_INT32 , GxB_ANY_ISLE_INT32 , - GxB_MIN_ISLE_UINT32 , GxB_MAX_ISLE_UINT32 , GxB_PLUS_ISLE_UINT32 , GxB_TIMES_ISLE_UINT32 , GxB_ANY_ISLE_UINT32 , - GxB_MIN_ISLE_INT64 , GxB_MAX_ISLE_INT64 , GxB_PLUS_ISLE_INT64 , GxB_TIMES_ISLE_INT64 , GxB_ANY_ISLE_INT64 , - GxB_MIN_ISLE_UINT64 , GxB_MAX_ISLE_UINT64 , GxB_PLUS_ISLE_UINT64 , GxB_TIMES_ISLE_UINT64 , GxB_ANY_ISLE_UINT64 , - GxB_MIN_ISLE_FP32 , GxB_MAX_ISLE_FP32 , GxB_PLUS_ISLE_FP32 , GxB_TIMES_ISLE_FP32 , GxB_ANY_ISLE_FP32 , - GxB_MIN_ISLE_FP64 , GxB_MAX_ISLE_FP64 , GxB_PLUS_ISLE_FP64 , GxB_TIMES_ISLE_FP64 , GxB_ANY_ISLE_FP64 , + GxB_MIN_ISLE_INT8 , GxB_MAX_ISLE_INT8 , GxB_PLUS_ISLE_INT8 , GxB_TIMES_ISLE_INT8 , GxB_ANY_ISLE_INT8 , + GxB_MIN_ISLE_INT16 , GxB_MAX_ISLE_INT16 , GxB_PLUS_ISLE_INT16 , GxB_TIMES_ISLE_INT16 , GxB_ANY_ISLE_INT16 , + GxB_MIN_ISLE_INT32 , GxB_MAX_ISLE_INT32 , GxB_PLUS_ISLE_INT32 , GxB_TIMES_ISLE_INT32 , GxB_ANY_ISLE_INT32 , + GxB_MIN_ISLE_INT64 , GxB_MAX_ISLE_INT64 , GxB_PLUS_ISLE_INT64 , GxB_TIMES_ISLE_INT64 , GxB_ANY_ISLE_INT64 , + GxB_MIN_ISLE_UINT8 , GxB_MAX_ISLE_UINT8 , GxB_PLUS_ISLE_UINT8 , GxB_TIMES_ISLE_UINT8 , GxB_ANY_ISLE_UINT8 , + GxB_MIN_ISLE_UINT16 , GxB_MAX_ISLE_UINT16 , GxB_PLUS_ISLE_UINT16 , GxB_TIMES_ISLE_UINT16 , GxB_ANY_ISLE_UINT16 , + GxB_MIN_ISLE_UINT32 , GxB_MAX_ISLE_UINT32 , GxB_PLUS_ISLE_UINT32 , GxB_TIMES_ISLE_UINT32 , GxB_ANY_ISLE_UINT32 , + GxB_MIN_ISLE_UINT64 , GxB_MAX_ISLE_UINT64 , GxB_PLUS_ISLE_UINT64 , GxB_TIMES_ISLE_UINT64 , GxB_ANY_ISLE_UINT64 , + GxB_MIN_ISLE_FP32 , GxB_MAX_ISLE_FP32 , GxB_PLUS_ISLE_FP32 , GxB_TIMES_ISLE_FP32 , GxB_ANY_ISLE_FP32 , + GxB_MIN_ISLE_FP64 , GxB_MAX_ISLE_FP64 , GxB_PLUS_ISLE_FP64 , GxB_TIMES_ISLE_FP64 , GxB_ANY_ISLE_FP64 , // semirings with multiply op: z = LOR (x,y), all types x,y,z the same: - GxB_MIN_LOR_INT8 , GxB_MAX_LOR_INT8 , GxB_PLUS_LOR_INT8 , GxB_TIMES_LOR_INT8 , GxB_ANY_LOR_INT8 , - GxB_MIN_LOR_UINT8 , GxB_MAX_LOR_UINT8 , GxB_PLUS_LOR_UINT8 , GxB_TIMES_LOR_UINT8 , GxB_ANY_LOR_UINT8 , - GxB_MIN_LOR_INT16 , GxB_MAX_LOR_INT16 , GxB_PLUS_LOR_INT16 , GxB_TIMES_LOR_INT16 , GxB_ANY_LOR_INT16 , - GxB_MIN_LOR_UINT16 , GxB_MAX_LOR_UINT16 , GxB_PLUS_LOR_UINT16 , GxB_TIMES_LOR_UINT16 , GxB_ANY_LOR_UINT16 , - GxB_MIN_LOR_INT32 , GxB_MAX_LOR_INT32 , GxB_PLUS_LOR_INT32 , GxB_TIMES_LOR_INT32 , GxB_ANY_LOR_INT32 , - GxB_MIN_LOR_UINT32 , GxB_MAX_LOR_UINT32 , GxB_PLUS_LOR_UINT32 , GxB_TIMES_LOR_UINT32 , GxB_ANY_LOR_UINT32 , - GxB_MIN_LOR_INT64 , GxB_MAX_LOR_INT64 , GxB_PLUS_LOR_INT64 , GxB_TIMES_LOR_INT64 , GxB_ANY_LOR_INT64 , - GxB_MIN_LOR_UINT64 , GxB_MAX_LOR_UINT64 , GxB_PLUS_LOR_UINT64 , GxB_TIMES_LOR_UINT64 , GxB_ANY_LOR_UINT64 , - GxB_MIN_LOR_FP32 , GxB_MAX_LOR_FP32 , GxB_PLUS_LOR_FP32 , GxB_TIMES_LOR_FP32 , GxB_ANY_LOR_FP32 , - GxB_MIN_LOR_FP64 , GxB_MAX_LOR_FP64 , GxB_PLUS_LOR_FP64 , GxB_TIMES_LOR_FP64 , GxB_ANY_LOR_FP64 , + GxB_MIN_LOR_INT8 , GxB_MAX_LOR_INT8 , GxB_PLUS_LOR_INT8 , GxB_TIMES_LOR_INT8 , GxB_ANY_LOR_INT8 , + GxB_MIN_LOR_INT16 , GxB_MAX_LOR_INT16 , GxB_PLUS_LOR_INT16 , GxB_TIMES_LOR_INT16 , GxB_ANY_LOR_INT16 , + GxB_MIN_LOR_INT32 , GxB_MAX_LOR_INT32 , GxB_PLUS_LOR_INT32 , GxB_TIMES_LOR_INT32 , GxB_ANY_LOR_INT32 , + GxB_MIN_LOR_INT64 , GxB_MAX_LOR_INT64 , GxB_PLUS_LOR_INT64 , GxB_TIMES_LOR_INT64 , GxB_ANY_LOR_INT64 , + GxB_MIN_LOR_UINT8 , GxB_MAX_LOR_UINT8 , GxB_PLUS_LOR_UINT8 , GxB_TIMES_LOR_UINT8 , GxB_ANY_LOR_UINT8 , + GxB_MIN_LOR_UINT16 , GxB_MAX_LOR_UINT16 , GxB_PLUS_LOR_UINT16 , GxB_TIMES_LOR_UINT16 , GxB_ANY_LOR_UINT16 , + GxB_MIN_LOR_UINT32 , GxB_MAX_LOR_UINT32 , GxB_PLUS_LOR_UINT32 , GxB_TIMES_LOR_UINT32 , GxB_ANY_LOR_UINT32 , + GxB_MIN_LOR_UINT64 , GxB_MAX_LOR_UINT64 , GxB_PLUS_LOR_UINT64 , GxB_TIMES_LOR_UINT64 , GxB_ANY_LOR_UINT64 , + GxB_MIN_LOR_FP32 , GxB_MAX_LOR_FP32 , GxB_PLUS_LOR_FP32 , GxB_TIMES_LOR_FP32 , GxB_ANY_LOR_FP32 , + GxB_MIN_LOR_FP64 , GxB_MAX_LOR_FP64 , GxB_PLUS_LOR_FP64 , GxB_TIMES_LOR_FP64 , GxB_ANY_LOR_FP64 , // semirings with multiply op: z = LAND (x,y), all types x,y,z the same: - GxB_MIN_LAND_INT8 , GxB_MAX_LAND_INT8 , GxB_PLUS_LAND_INT8 , GxB_TIMES_LAND_INT8 , GxB_ANY_LAND_INT8 , - GxB_MIN_LAND_UINT8 , GxB_MAX_LAND_UINT8 , GxB_PLUS_LAND_UINT8 , GxB_TIMES_LAND_UINT8 , GxB_ANY_LAND_UINT8 , - GxB_MIN_LAND_INT16 , GxB_MAX_LAND_INT16 , GxB_PLUS_LAND_INT16 , GxB_TIMES_LAND_INT16 , GxB_ANY_LAND_INT16 , - GxB_MIN_LAND_UINT16 , GxB_MAX_LAND_UINT16 , GxB_PLUS_LAND_UINT16 , GxB_TIMES_LAND_UINT16 , GxB_ANY_LAND_UINT16 , - GxB_MIN_LAND_INT32 , GxB_MAX_LAND_INT32 , GxB_PLUS_LAND_INT32 , GxB_TIMES_LAND_INT32 , GxB_ANY_LAND_INT32 , - GxB_MIN_LAND_UINT32 , GxB_MAX_LAND_UINT32 , GxB_PLUS_LAND_UINT32 , GxB_TIMES_LAND_UINT32 , GxB_ANY_LAND_UINT32 , - GxB_MIN_LAND_INT64 , GxB_MAX_LAND_INT64 , GxB_PLUS_LAND_INT64 , GxB_TIMES_LAND_INT64 , GxB_ANY_LAND_INT64 , - GxB_MIN_LAND_UINT64 , GxB_MAX_LAND_UINT64 , GxB_PLUS_LAND_UINT64 , GxB_TIMES_LAND_UINT64 , GxB_ANY_LAND_UINT64 , - GxB_MIN_LAND_FP32 , GxB_MAX_LAND_FP32 , GxB_PLUS_LAND_FP32 , GxB_TIMES_LAND_FP32 , GxB_ANY_LAND_FP32 , - GxB_MIN_LAND_FP64 , GxB_MAX_LAND_FP64 , GxB_PLUS_LAND_FP64 , GxB_TIMES_LAND_FP64 , GxB_ANY_LAND_FP64 , + GxB_MIN_LAND_INT8 , GxB_MAX_LAND_INT8 , GxB_PLUS_LAND_INT8 , GxB_TIMES_LAND_INT8 , GxB_ANY_LAND_INT8 , + GxB_MIN_LAND_INT16 , GxB_MAX_LAND_INT16 , GxB_PLUS_LAND_INT16 , GxB_TIMES_LAND_INT16 , GxB_ANY_LAND_INT16 , + GxB_MIN_LAND_INT32 , GxB_MAX_LAND_INT32 , GxB_PLUS_LAND_INT32 , GxB_TIMES_LAND_INT32 , GxB_ANY_LAND_INT32 , + GxB_MIN_LAND_INT64 , GxB_MAX_LAND_INT64 , GxB_PLUS_LAND_INT64 , GxB_TIMES_LAND_INT64 , GxB_ANY_LAND_INT64 , + GxB_MIN_LAND_UINT8 , GxB_MAX_LAND_UINT8 , GxB_PLUS_LAND_UINT8 , GxB_TIMES_LAND_UINT8 , GxB_ANY_LAND_UINT8 , + GxB_MIN_LAND_UINT16 , GxB_MAX_LAND_UINT16 , GxB_PLUS_LAND_UINT16 , GxB_TIMES_LAND_UINT16 , GxB_ANY_LAND_UINT16 , + GxB_MIN_LAND_UINT32 , GxB_MAX_LAND_UINT32 , GxB_PLUS_LAND_UINT32 , GxB_TIMES_LAND_UINT32 , GxB_ANY_LAND_UINT32 , + GxB_MIN_LAND_UINT64 , GxB_MAX_LAND_UINT64 , GxB_PLUS_LAND_UINT64 , GxB_TIMES_LAND_UINT64 , GxB_ANY_LAND_UINT64 , + GxB_MIN_LAND_FP32 , GxB_MAX_LAND_FP32 , GxB_PLUS_LAND_FP32 , GxB_TIMES_LAND_FP32 , GxB_ANY_LAND_FP32 , + GxB_MIN_LAND_FP64 , GxB_MAX_LAND_FP64 , GxB_PLUS_LAND_FP64 , GxB_TIMES_LAND_FP64 , GxB_ANY_LAND_FP64 , // semirings with multiply op: z = LXOR (x,y), all types x,y,z the same: - GxB_MIN_LXOR_INT8 , GxB_MAX_LXOR_INT8 , GxB_PLUS_LXOR_INT8 , GxB_TIMES_LXOR_INT8 , GxB_ANY_LXOR_INT8 , - GxB_MIN_LXOR_UINT8 , GxB_MAX_LXOR_UINT8 , GxB_PLUS_LXOR_UINT8 , GxB_TIMES_LXOR_UINT8 , GxB_ANY_LXOR_UINT8 , - GxB_MIN_LXOR_INT16 , GxB_MAX_LXOR_INT16 , GxB_PLUS_LXOR_INT16 , GxB_TIMES_LXOR_INT16 , GxB_ANY_LXOR_INT16 , - GxB_MIN_LXOR_UINT16 , GxB_MAX_LXOR_UINT16 , GxB_PLUS_LXOR_UINT16 , GxB_TIMES_LXOR_UINT16 , GxB_ANY_LXOR_UINT16 , - GxB_MIN_LXOR_INT32 , GxB_MAX_LXOR_INT32 , GxB_PLUS_LXOR_INT32 , GxB_TIMES_LXOR_INT32 , GxB_ANY_LXOR_INT32 , - GxB_MIN_LXOR_UINT32 , GxB_MAX_LXOR_UINT32 , GxB_PLUS_LXOR_UINT32 , GxB_TIMES_LXOR_UINT32 , GxB_ANY_LXOR_UINT32 , - GxB_MIN_LXOR_INT64 , GxB_MAX_LXOR_INT64 , GxB_PLUS_LXOR_INT64 , GxB_TIMES_LXOR_INT64 , GxB_ANY_LXOR_INT64 , - GxB_MIN_LXOR_UINT64 , GxB_MAX_LXOR_UINT64 , GxB_PLUS_LXOR_UINT64 , GxB_TIMES_LXOR_UINT64 , GxB_ANY_LXOR_UINT64 , - GxB_MIN_LXOR_FP32 , GxB_MAX_LXOR_FP32 , GxB_PLUS_LXOR_FP32 , GxB_TIMES_LXOR_FP32 , GxB_ANY_LXOR_FP32 , - GxB_MIN_LXOR_FP64 , GxB_MAX_LXOR_FP64 , GxB_PLUS_LXOR_FP64 , GxB_TIMES_LXOR_FP64 , GxB_ANY_LXOR_FP64 , + GxB_MIN_LXOR_INT8 , GxB_MAX_LXOR_INT8 , GxB_PLUS_LXOR_INT8 , GxB_TIMES_LXOR_INT8 , GxB_ANY_LXOR_INT8 , + GxB_MIN_LXOR_INT16 , GxB_MAX_LXOR_INT16 , GxB_PLUS_LXOR_INT16 , GxB_TIMES_LXOR_INT16 , GxB_ANY_LXOR_INT16 , + GxB_MIN_LXOR_INT32 , GxB_MAX_LXOR_INT32 , GxB_PLUS_LXOR_INT32 , GxB_TIMES_LXOR_INT32 , GxB_ANY_LXOR_INT32 , + GxB_MIN_LXOR_INT64 , GxB_MAX_LXOR_INT64 , GxB_PLUS_LXOR_INT64 , GxB_TIMES_LXOR_INT64 , GxB_ANY_LXOR_INT64 , + GxB_MIN_LXOR_UINT8 , GxB_MAX_LXOR_UINT8 , GxB_PLUS_LXOR_UINT8 , GxB_TIMES_LXOR_UINT8 , GxB_ANY_LXOR_UINT8 , + GxB_MIN_LXOR_UINT16 , GxB_MAX_LXOR_UINT16 , GxB_PLUS_LXOR_UINT16 , GxB_TIMES_LXOR_UINT16 , GxB_ANY_LXOR_UINT16 , + GxB_MIN_LXOR_UINT32 , GxB_MAX_LXOR_UINT32 , GxB_PLUS_LXOR_UINT32 , GxB_TIMES_LXOR_UINT32 , GxB_ANY_LXOR_UINT32 , + GxB_MIN_LXOR_UINT64 , GxB_MAX_LXOR_UINT64 , GxB_PLUS_LXOR_UINT64 , GxB_TIMES_LXOR_UINT64 , GxB_ANY_LXOR_UINT64 , + GxB_MIN_LXOR_FP32 , GxB_MAX_LXOR_FP32 , GxB_PLUS_LXOR_FP32 , GxB_TIMES_LXOR_FP32 , GxB_ANY_LXOR_FP32 , + GxB_MIN_LXOR_FP64 , GxB_MAX_LXOR_FP64 , GxB_PLUS_LXOR_FP64 , GxB_TIMES_LXOR_FP64 , GxB_ANY_LXOR_FP64 , //------------------------------------------------------------------------------ // 300 semirings with a comparison operator TxT -> bool, where T is non-Boolean //------------------------------------------------------------------------------ // semirings with multiply op: z = EQ (x,y), where z is boolean and x,y are given by the suffix: - GxB_LOR_EQ_INT8 , GxB_LAND_EQ_INT8 , GxB_LXOR_EQ_INT8 , GxB_EQ_EQ_INT8 , GxB_ANY_EQ_INT8 , - GxB_LOR_EQ_UINT8 , GxB_LAND_EQ_UINT8 , GxB_LXOR_EQ_UINT8 , GxB_EQ_EQ_UINT8 , GxB_ANY_EQ_UINT8 , - GxB_LOR_EQ_INT16 , GxB_LAND_EQ_INT16 , GxB_LXOR_EQ_INT16 , GxB_EQ_EQ_INT16 , GxB_ANY_EQ_INT16 , - GxB_LOR_EQ_UINT16 , GxB_LAND_EQ_UINT16 , GxB_LXOR_EQ_UINT16 , GxB_EQ_EQ_UINT16 , GxB_ANY_EQ_UINT16 , - GxB_LOR_EQ_INT32 , GxB_LAND_EQ_INT32 , GxB_LXOR_EQ_INT32 , GxB_EQ_EQ_INT32 , GxB_ANY_EQ_INT32 , - GxB_LOR_EQ_UINT32 , GxB_LAND_EQ_UINT32 , GxB_LXOR_EQ_UINT32 , GxB_EQ_EQ_UINT32 , GxB_ANY_EQ_UINT32 , - GxB_LOR_EQ_INT64 , GxB_LAND_EQ_INT64 , GxB_LXOR_EQ_INT64 , GxB_EQ_EQ_INT64 , GxB_ANY_EQ_INT64 , - GxB_LOR_EQ_UINT64 , GxB_LAND_EQ_UINT64 , GxB_LXOR_EQ_UINT64 , GxB_EQ_EQ_UINT64 , GxB_ANY_EQ_UINT64 , - GxB_LOR_EQ_FP32 , GxB_LAND_EQ_FP32 , GxB_LXOR_EQ_FP32 , GxB_EQ_EQ_FP32 , GxB_ANY_EQ_FP32 , - GxB_LOR_EQ_FP64 , GxB_LAND_EQ_FP64 , GxB_LXOR_EQ_FP64 , GxB_EQ_EQ_FP64 , GxB_ANY_EQ_FP64 , + GxB_LOR_EQ_INT8 , GxB_LAND_EQ_INT8 , GxB_LXOR_EQ_INT8 , GxB_EQ_EQ_INT8 , GxB_ANY_EQ_INT8 , + GxB_LOR_EQ_INT16 , GxB_LAND_EQ_INT16 , GxB_LXOR_EQ_INT16 , GxB_EQ_EQ_INT16 , GxB_ANY_EQ_INT16 , + GxB_LOR_EQ_INT32 , GxB_LAND_EQ_INT32 , GxB_LXOR_EQ_INT32 , GxB_EQ_EQ_INT32 , GxB_ANY_EQ_INT32 , + GxB_LOR_EQ_INT64 , GxB_LAND_EQ_INT64 , GxB_LXOR_EQ_INT64 , GxB_EQ_EQ_INT64 , GxB_ANY_EQ_INT64 , + GxB_LOR_EQ_UINT8 , GxB_LAND_EQ_UINT8 , GxB_LXOR_EQ_UINT8 , GxB_EQ_EQ_UINT8 , GxB_ANY_EQ_UINT8 , + GxB_LOR_EQ_UINT16 , GxB_LAND_EQ_UINT16 , GxB_LXOR_EQ_UINT16 , GxB_EQ_EQ_UINT16 , GxB_ANY_EQ_UINT16 , + GxB_LOR_EQ_UINT32 , GxB_LAND_EQ_UINT32 , GxB_LXOR_EQ_UINT32 , GxB_EQ_EQ_UINT32 , GxB_ANY_EQ_UINT32 , + GxB_LOR_EQ_UINT64 , GxB_LAND_EQ_UINT64 , GxB_LXOR_EQ_UINT64 , GxB_EQ_EQ_UINT64 , GxB_ANY_EQ_UINT64 , + GxB_LOR_EQ_FP32 , GxB_LAND_EQ_FP32 , GxB_LXOR_EQ_FP32 , GxB_EQ_EQ_FP32 , GxB_ANY_EQ_FP32 , + GxB_LOR_EQ_FP64 , GxB_LAND_EQ_FP64 , GxB_LXOR_EQ_FP64 , GxB_EQ_EQ_FP64 , GxB_ANY_EQ_FP64 , // semirings with multiply op: z = NE (x,y), where z is boolean and x,y are given by the suffix: - GxB_LOR_NE_INT8 , GxB_LAND_NE_INT8 , GxB_LXOR_NE_INT8 , GxB_EQ_NE_INT8 , GxB_ANY_NE_INT8 , - GxB_LOR_NE_UINT8 , GxB_LAND_NE_UINT8 , GxB_LXOR_NE_UINT8 , GxB_EQ_NE_UINT8 , GxB_ANY_NE_UINT8 , - GxB_LOR_NE_INT16 , GxB_LAND_NE_INT16 , GxB_LXOR_NE_INT16 , GxB_EQ_NE_INT16 , GxB_ANY_NE_INT16 , - GxB_LOR_NE_UINT16 , GxB_LAND_NE_UINT16 , GxB_LXOR_NE_UINT16 , GxB_EQ_NE_UINT16 , GxB_ANY_NE_UINT16 , - GxB_LOR_NE_INT32 , GxB_LAND_NE_INT32 , GxB_LXOR_NE_INT32 , GxB_EQ_NE_INT32 , GxB_ANY_NE_INT32 , - GxB_LOR_NE_UINT32 , GxB_LAND_NE_UINT32 , GxB_LXOR_NE_UINT32 , GxB_EQ_NE_UINT32 , GxB_ANY_NE_UINT32 , - GxB_LOR_NE_INT64 , GxB_LAND_NE_INT64 , GxB_LXOR_NE_INT64 , GxB_EQ_NE_INT64 , GxB_ANY_NE_INT64 , - GxB_LOR_NE_UINT64 , GxB_LAND_NE_UINT64 , GxB_LXOR_NE_UINT64 , GxB_EQ_NE_UINT64 , GxB_ANY_NE_UINT64 , - GxB_LOR_NE_FP32 , GxB_LAND_NE_FP32 , GxB_LXOR_NE_FP32 , GxB_EQ_NE_FP32 , GxB_ANY_NE_FP32 , - GxB_LOR_NE_FP64 , GxB_LAND_NE_FP64 , GxB_LXOR_NE_FP64 , GxB_EQ_NE_FP64 , GxB_ANY_NE_FP64 , + GxB_LOR_NE_INT8 , GxB_LAND_NE_INT8 , GxB_LXOR_NE_INT8 , GxB_EQ_NE_INT8 , GxB_ANY_NE_INT8 , + GxB_LOR_NE_INT16 , GxB_LAND_NE_INT16 , GxB_LXOR_NE_INT16 , GxB_EQ_NE_INT16 , GxB_ANY_NE_INT16 , + GxB_LOR_NE_INT32 , GxB_LAND_NE_INT32 , GxB_LXOR_NE_INT32 , GxB_EQ_NE_INT32 , GxB_ANY_NE_INT32 , + GxB_LOR_NE_INT64 , GxB_LAND_NE_INT64 , GxB_LXOR_NE_INT64 , GxB_EQ_NE_INT64 , GxB_ANY_NE_INT64 , + GxB_LOR_NE_UINT8 , GxB_LAND_NE_UINT8 , GxB_LXOR_NE_UINT8 , GxB_EQ_NE_UINT8 , GxB_ANY_NE_UINT8 , + GxB_LOR_NE_UINT16 , GxB_LAND_NE_UINT16 , GxB_LXOR_NE_UINT16 , GxB_EQ_NE_UINT16 , GxB_ANY_NE_UINT16 , + GxB_LOR_NE_UINT32 , GxB_LAND_NE_UINT32 , GxB_LXOR_NE_UINT32 , GxB_EQ_NE_UINT32 , GxB_ANY_NE_UINT32 , + GxB_LOR_NE_UINT64 , GxB_LAND_NE_UINT64 , GxB_LXOR_NE_UINT64 , GxB_EQ_NE_UINT64 , GxB_ANY_NE_UINT64 , + GxB_LOR_NE_FP32 , GxB_LAND_NE_FP32 , GxB_LXOR_NE_FP32 , GxB_EQ_NE_FP32 , GxB_ANY_NE_FP32 , + GxB_LOR_NE_FP64 , GxB_LAND_NE_FP64 , GxB_LXOR_NE_FP64 , GxB_EQ_NE_FP64 , GxB_ANY_NE_FP64 , // semirings with multiply op: z = GT (x,y), where z is boolean and x,y are given by the suffix: - GxB_LOR_GT_INT8 , GxB_LAND_GT_INT8 , GxB_LXOR_GT_INT8 , GxB_EQ_GT_INT8 , GxB_ANY_GT_INT8 , - GxB_LOR_GT_UINT8 , GxB_LAND_GT_UINT8 , GxB_LXOR_GT_UINT8 , GxB_EQ_GT_UINT8 , GxB_ANY_GT_UINT8 , - GxB_LOR_GT_INT16 , GxB_LAND_GT_INT16 , GxB_LXOR_GT_INT16 , GxB_EQ_GT_INT16 , GxB_ANY_GT_INT16 , - GxB_LOR_GT_UINT16 , GxB_LAND_GT_UINT16 , GxB_LXOR_GT_UINT16 , GxB_EQ_GT_UINT16 , GxB_ANY_GT_UINT16 , - GxB_LOR_GT_INT32 , GxB_LAND_GT_INT32 , GxB_LXOR_GT_INT32 , GxB_EQ_GT_INT32 , GxB_ANY_GT_INT32 , - GxB_LOR_GT_UINT32 , GxB_LAND_GT_UINT32 , GxB_LXOR_GT_UINT32 , GxB_EQ_GT_UINT32 , GxB_ANY_GT_UINT32 , - GxB_LOR_GT_INT64 , GxB_LAND_GT_INT64 , GxB_LXOR_GT_INT64 , GxB_EQ_GT_INT64 , GxB_ANY_GT_INT64 , - GxB_LOR_GT_UINT64 , GxB_LAND_GT_UINT64 , GxB_LXOR_GT_UINT64 , GxB_EQ_GT_UINT64 , GxB_ANY_GT_UINT64 , - GxB_LOR_GT_FP32 , GxB_LAND_GT_FP32 , GxB_LXOR_GT_FP32 , GxB_EQ_GT_FP32 , GxB_ANY_GT_FP32 , - GxB_LOR_GT_FP64 , GxB_LAND_GT_FP64 , GxB_LXOR_GT_FP64 , GxB_EQ_GT_FP64 , GxB_ANY_GT_FP64 , + GxB_LOR_GT_INT8 , GxB_LAND_GT_INT8 , GxB_LXOR_GT_INT8 , GxB_EQ_GT_INT8 , GxB_ANY_GT_INT8 , + GxB_LOR_GT_INT16 , GxB_LAND_GT_INT16 , GxB_LXOR_GT_INT16 , GxB_EQ_GT_INT16 , GxB_ANY_GT_INT16 , + GxB_LOR_GT_INT32 , GxB_LAND_GT_INT32 , GxB_LXOR_GT_INT32 , GxB_EQ_GT_INT32 , GxB_ANY_GT_INT32 , + GxB_LOR_GT_INT64 , GxB_LAND_GT_INT64 , GxB_LXOR_GT_INT64 , GxB_EQ_GT_INT64 , GxB_ANY_GT_INT64 , + GxB_LOR_GT_UINT8 , GxB_LAND_GT_UINT8 , GxB_LXOR_GT_UINT8 , GxB_EQ_GT_UINT8 , GxB_ANY_GT_UINT8 , + GxB_LOR_GT_UINT16 , GxB_LAND_GT_UINT16 , GxB_LXOR_GT_UINT16 , GxB_EQ_GT_UINT16 , GxB_ANY_GT_UINT16 , + GxB_LOR_GT_UINT32 , GxB_LAND_GT_UINT32 , GxB_LXOR_GT_UINT32 , GxB_EQ_GT_UINT32 , GxB_ANY_GT_UINT32 , + GxB_LOR_GT_UINT64 , GxB_LAND_GT_UINT64 , GxB_LXOR_GT_UINT64 , GxB_EQ_GT_UINT64 , GxB_ANY_GT_UINT64 , + GxB_LOR_GT_FP32 , GxB_LAND_GT_FP32 , GxB_LXOR_GT_FP32 , GxB_EQ_GT_FP32 , GxB_ANY_GT_FP32 , + GxB_LOR_GT_FP64 , GxB_LAND_GT_FP64 , GxB_LXOR_GT_FP64 , GxB_EQ_GT_FP64 , GxB_ANY_GT_FP64 , // semirings with multiply op: z = LT (x,y), where z is boolean and x,y are given by the suffix: - GxB_LOR_LT_INT8 , GxB_LAND_LT_INT8 , GxB_LXOR_LT_INT8 , GxB_EQ_LT_INT8 , GxB_ANY_LT_INT8 , - GxB_LOR_LT_UINT8 , GxB_LAND_LT_UINT8 , GxB_LXOR_LT_UINT8 , GxB_EQ_LT_UINT8 , GxB_ANY_LT_UINT8 , - GxB_LOR_LT_INT16 , GxB_LAND_LT_INT16 , GxB_LXOR_LT_INT16 , GxB_EQ_LT_INT16 , GxB_ANY_LT_INT16 , - GxB_LOR_LT_UINT16 , GxB_LAND_LT_UINT16 , GxB_LXOR_LT_UINT16 , GxB_EQ_LT_UINT16 , GxB_ANY_LT_UINT16 , - GxB_LOR_LT_INT32 , GxB_LAND_LT_INT32 , GxB_LXOR_LT_INT32 , GxB_EQ_LT_INT32 , GxB_ANY_LT_INT32 , - GxB_LOR_LT_UINT32 , GxB_LAND_LT_UINT32 , GxB_LXOR_LT_UINT32 , GxB_EQ_LT_UINT32 , GxB_ANY_LT_UINT32 , - GxB_LOR_LT_INT64 , GxB_LAND_LT_INT64 , GxB_LXOR_LT_INT64 , GxB_EQ_LT_INT64 , GxB_ANY_LT_INT64 , - GxB_LOR_LT_UINT64 , GxB_LAND_LT_UINT64 , GxB_LXOR_LT_UINT64 , GxB_EQ_LT_UINT64 , GxB_ANY_LT_UINT64 , - GxB_LOR_LT_FP32 , GxB_LAND_LT_FP32 , GxB_LXOR_LT_FP32 , GxB_EQ_LT_FP32 , GxB_ANY_LT_FP32 , - GxB_LOR_LT_FP64 , GxB_LAND_LT_FP64 , GxB_LXOR_LT_FP64 , GxB_EQ_LT_FP64 , GxB_ANY_LT_FP64 , + GxB_LOR_LT_INT8 , GxB_LAND_LT_INT8 , GxB_LXOR_LT_INT8 , GxB_EQ_LT_INT8 , GxB_ANY_LT_INT8 , + GxB_LOR_LT_INT16 , GxB_LAND_LT_INT16 , GxB_LXOR_LT_INT16 , GxB_EQ_LT_INT16 , GxB_ANY_LT_INT16 , + GxB_LOR_LT_INT32 , GxB_LAND_LT_INT32 , GxB_LXOR_LT_INT32 , GxB_EQ_LT_INT32 , GxB_ANY_LT_INT32 , + GxB_LOR_LT_INT64 , GxB_LAND_LT_INT64 , GxB_LXOR_LT_INT64 , GxB_EQ_LT_INT64 , GxB_ANY_LT_INT64 , + GxB_LOR_LT_UINT8 , GxB_LAND_LT_UINT8 , GxB_LXOR_LT_UINT8 , GxB_EQ_LT_UINT8 , GxB_ANY_LT_UINT8 , + GxB_LOR_LT_UINT16 , GxB_LAND_LT_UINT16 , GxB_LXOR_LT_UINT16 , GxB_EQ_LT_UINT16 , GxB_ANY_LT_UINT16 , + GxB_LOR_LT_UINT32 , GxB_LAND_LT_UINT32 , GxB_LXOR_LT_UINT32 , GxB_EQ_LT_UINT32 , GxB_ANY_LT_UINT32 , + GxB_LOR_LT_UINT64 , GxB_LAND_LT_UINT64 , GxB_LXOR_LT_UINT64 , GxB_EQ_LT_UINT64 , GxB_ANY_LT_UINT64 , + GxB_LOR_LT_FP32 , GxB_LAND_LT_FP32 , GxB_LXOR_LT_FP32 , GxB_EQ_LT_FP32 , GxB_ANY_LT_FP32 , + GxB_LOR_LT_FP64 , GxB_LAND_LT_FP64 , GxB_LXOR_LT_FP64 , GxB_EQ_LT_FP64 , GxB_ANY_LT_FP64 , // semirings with multiply op: z = GE (x,y), where z is boolean and x,y are given by the suffix: - GxB_LOR_GE_INT8 , GxB_LAND_GE_INT8 , GxB_LXOR_GE_INT8 , GxB_EQ_GE_INT8 , GxB_ANY_GE_INT8 , - GxB_LOR_GE_UINT8 , GxB_LAND_GE_UINT8 , GxB_LXOR_GE_UINT8 , GxB_EQ_GE_UINT8 , GxB_ANY_GE_UINT8 , - GxB_LOR_GE_INT16 , GxB_LAND_GE_INT16 , GxB_LXOR_GE_INT16 , GxB_EQ_GE_INT16 , GxB_ANY_GE_INT16 , - GxB_LOR_GE_UINT16 , GxB_LAND_GE_UINT16 , GxB_LXOR_GE_UINT16 , GxB_EQ_GE_UINT16 , GxB_ANY_GE_UINT16 , - GxB_LOR_GE_INT32 , GxB_LAND_GE_INT32 , GxB_LXOR_GE_INT32 , GxB_EQ_GE_INT32 , GxB_ANY_GE_INT32 , - GxB_LOR_GE_UINT32 , GxB_LAND_GE_UINT32 , GxB_LXOR_GE_UINT32 , GxB_EQ_GE_UINT32 , GxB_ANY_GE_UINT32 , - GxB_LOR_GE_INT64 , GxB_LAND_GE_INT64 , GxB_LXOR_GE_INT64 , GxB_EQ_GE_INT64 , GxB_ANY_GE_INT64 , - GxB_LOR_GE_UINT64 , GxB_LAND_GE_UINT64 , GxB_LXOR_GE_UINT64 , GxB_EQ_GE_UINT64 , GxB_ANY_GE_UINT64 , - GxB_LOR_GE_FP32 , GxB_LAND_GE_FP32 , GxB_LXOR_GE_FP32 , GxB_EQ_GE_FP32 , GxB_ANY_GE_FP32 , - GxB_LOR_GE_FP64 , GxB_LAND_GE_FP64 , GxB_LXOR_GE_FP64 , GxB_EQ_GE_FP64 , GxB_ANY_GE_FP64 , + GxB_LOR_GE_INT8 , GxB_LAND_GE_INT8 , GxB_LXOR_GE_INT8 , GxB_EQ_GE_INT8 , GxB_ANY_GE_INT8 , + GxB_LOR_GE_INT16 , GxB_LAND_GE_INT16 , GxB_LXOR_GE_INT16 , GxB_EQ_GE_INT16 , GxB_ANY_GE_INT16 , + GxB_LOR_GE_INT32 , GxB_LAND_GE_INT32 , GxB_LXOR_GE_INT32 , GxB_EQ_GE_INT32 , GxB_ANY_GE_INT32 , + GxB_LOR_GE_INT64 , GxB_LAND_GE_INT64 , GxB_LXOR_GE_INT64 , GxB_EQ_GE_INT64 , GxB_ANY_GE_INT64 , + GxB_LOR_GE_UINT8 , GxB_LAND_GE_UINT8 , GxB_LXOR_GE_UINT8 , GxB_EQ_GE_UINT8 , GxB_ANY_GE_UINT8 , + GxB_LOR_GE_UINT16 , GxB_LAND_GE_UINT16 , GxB_LXOR_GE_UINT16 , GxB_EQ_GE_UINT16 , GxB_ANY_GE_UINT16 , + GxB_LOR_GE_UINT32 , GxB_LAND_GE_UINT32 , GxB_LXOR_GE_UINT32 , GxB_EQ_GE_UINT32 , GxB_ANY_GE_UINT32 , + GxB_LOR_GE_UINT64 , GxB_LAND_GE_UINT64 , GxB_LXOR_GE_UINT64 , GxB_EQ_GE_UINT64 , GxB_ANY_GE_UINT64 , + GxB_LOR_GE_FP32 , GxB_LAND_GE_FP32 , GxB_LXOR_GE_FP32 , GxB_EQ_GE_FP32 , GxB_ANY_GE_FP32 , + GxB_LOR_GE_FP64 , GxB_LAND_GE_FP64 , GxB_LXOR_GE_FP64 , GxB_EQ_GE_FP64 , GxB_ANY_GE_FP64 , // semirings with multiply op: z = LE (x,y), where z is boolean and x,y are given by the suffix: - GxB_LOR_LE_INT8 , GxB_LAND_LE_INT8 , GxB_LXOR_LE_INT8 , GxB_EQ_LE_INT8 , GxB_ANY_LE_INT8 , - GxB_LOR_LE_UINT8 , GxB_LAND_LE_UINT8 , GxB_LXOR_LE_UINT8 , GxB_EQ_LE_UINT8 , GxB_ANY_LE_UINT8 , - GxB_LOR_LE_INT16 , GxB_LAND_LE_INT16 , GxB_LXOR_LE_INT16 , GxB_EQ_LE_INT16 , GxB_ANY_LE_INT16 , - GxB_LOR_LE_UINT16 , GxB_LAND_LE_UINT16 , GxB_LXOR_LE_UINT16 , GxB_EQ_LE_UINT16 , GxB_ANY_LE_UINT16 , - GxB_LOR_LE_INT32 , GxB_LAND_LE_INT32 , GxB_LXOR_LE_INT32 , GxB_EQ_LE_INT32 , GxB_ANY_LE_INT32 , - GxB_LOR_LE_UINT32 , GxB_LAND_LE_UINT32 , GxB_LXOR_LE_UINT32 , GxB_EQ_LE_UINT32 , GxB_ANY_LE_UINT32 , - GxB_LOR_LE_INT64 , GxB_LAND_LE_INT64 , GxB_LXOR_LE_INT64 , GxB_EQ_LE_INT64 , GxB_ANY_LE_INT64 , - GxB_LOR_LE_UINT64 , GxB_LAND_LE_UINT64 , GxB_LXOR_LE_UINT64 , GxB_EQ_LE_UINT64 , GxB_ANY_LE_UINT64 , - GxB_LOR_LE_FP32 , GxB_LAND_LE_FP32 , GxB_LXOR_LE_FP32 , GxB_EQ_LE_FP32 , GxB_ANY_LE_FP32 , - GxB_LOR_LE_FP64 , GxB_LAND_LE_FP64 , GxB_LXOR_LE_FP64 , GxB_EQ_LE_FP64 , GxB_ANY_LE_FP64 , + GxB_LOR_LE_INT8 , GxB_LAND_LE_INT8 , GxB_LXOR_LE_INT8 , GxB_EQ_LE_INT8 , GxB_ANY_LE_INT8 , + GxB_LOR_LE_INT16 , GxB_LAND_LE_INT16 , GxB_LXOR_LE_INT16 , GxB_EQ_LE_INT16 , GxB_ANY_LE_INT16 , + GxB_LOR_LE_INT32 , GxB_LAND_LE_INT32 , GxB_LXOR_LE_INT32 , GxB_EQ_LE_INT32 , GxB_ANY_LE_INT32 , + GxB_LOR_LE_INT64 , GxB_LAND_LE_INT64 , GxB_LXOR_LE_INT64 , GxB_EQ_LE_INT64 , GxB_ANY_LE_INT64 , + GxB_LOR_LE_UINT8 , GxB_LAND_LE_UINT8 , GxB_LXOR_LE_UINT8 , GxB_EQ_LE_UINT8 , GxB_ANY_LE_UINT8 , + GxB_LOR_LE_UINT16 , GxB_LAND_LE_UINT16 , GxB_LXOR_LE_UINT16 , GxB_EQ_LE_UINT16 , GxB_ANY_LE_UINT16 , + GxB_LOR_LE_UINT32 , GxB_LAND_LE_UINT32 , GxB_LXOR_LE_UINT32 , GxB_EQ_LE_UINT32 , GxB_ANY_LE_UINT32 , + GxB_LOR_LE_UINT64 , GxB_LAND_LE_UINT64 , GxB_LXOR_LE_UINT64 , GxB_EQ_LE_UINT64 , GxB_ANY_LE_UINT64 , + GxB_LOR_LE_FP32 , GxB_LAND_LE_FP32 , GxB_LXOR_LE_FP32 , GxB_EQ_LE_FP32 , GxB_ANY_LE_FP32 , + GxB_LOR_LE_FP64 , GxB_LAND_LE_FP64 , GxB_LXOR_LE_FP64 , GxB_EQ_LE_FP64 , GxB_ANY_LE_FP64 , //------------------------------------------------------------------------------ // 55 semirings with purely Boolean types, bool x bool -> bool //------------------------------------------------------------------------------ + // Note that lor_pair, land_pair, and eq_pair are all identical to any_pair. + // These 3 are marked below. + // purely boolean semirings (in the form GxB_(add monoid)_(multipy operator)_BOOL: - GxB_LOR_FIRST_BOOL , GxB_LAND_FIRST_BOOL , GxB_LXOR_FIRST_BOOL , GxB_EQ_FIRST_BOOL , GxB_ANY_FIRST_BOOL , - GxB_LOR_SECOND_BOOL , GxB_LAND_SECOND_BOOL , GxB_LXOR_SECOND_BOOL , GxB_EQ_SECOND_BOOL , GxB_ANY_SECOND_BOOL , - GxB_LOR_PAIR_BOOL , GxB_LAND_PAIR_BOOL , GxB_LXOR_PAIR_BOOL , GxB_EQ_PAIR_BOOL , GxB_ANY_PAIR_BOOL , - GxB_LOR_LOR_BOOL , GxB_LAND_LOR_BOOL , GxB_LXOR_LOR_BOOL , GxB_EQ_LOR_BOOL , GxB_ANY_LOR_BOOL , - GxB_LOR_LAND_BOOL , GxB_LAND_LAND_BOOL , GxB_LXOR_LAND_BOOL , GxB_EQ_LAND_BOOL , GxB_ANY_LAND_BOOL , - GxB_LOR_LXOR_BOOL , GxB_LAND_LXOR_BOOL , GxB_LXOR_LXOR_BOOL , GxB_EQ_LXOR_BOOL , GxB_ANY_LXOR_BOOL , - GxB_LOR_EQ_BOOL , GxB_LAND_EQ_BOOL , GxB_LXOR_EQ_BOOL , GxB_EQ_EQ_BOOL , GxB_ANY_EQ_BOOL , - GxB_LOR_GT_BOOL , GxB_LAND_GT_BOOL , GxB_LXOR_GT_BOOL , GxB_EQ_GT_BOOL , GxB_ANY_GT_BOOL , - GxB_LOR_LT_BOOL , GxB_LAND_LT_BOOL , GxB_LXOR_LT_BOOL , GxB_EQ_LT_BOOL , GxB_ANY_LT_BOOL , - GxB_LOR_GE_BOOL , GxB_LAND_GE_BOOL , GxB_LXOR_GE_BOOL , GxB_EQ_GE_BOOL , GxB_ANY_GE_BOOL , - GxB_LOR_LE_BOOL , GxB_LAND_LE_BOOL , GxB_LXOR_LE_BOOL , GxB_EQ_LE_BOOL , GxB_ANY_LE_BOOL ; + GxB_LOR_FIRST_BOOL , GxB_LAND_FIRST_BOOL , GxB_LXOR_FIRST_BOOL , GxB_EQ_FIRST_BOOL , GxB_ANY_FIRST_BOOL , + GxB_LOR_SECOND_BOOL , GxB_LAND_SECOND_BOOL , GxB_LXOR_SECOND_BOOL , GxB_EQ_SECOND_BOOL , GxB_ANY_SECOND_BOOL , + GxB_LOR_PAIR_BOOL/**/ , GxB_LAND_PAIR_BOOL/**/ , GxB_LXOR_PAIR_BOOL , GxB_EQ_PAIR_BOOL/**/ , GxB_ANY_PAIR_BOOL , + GxB_LOR_LOR_BOOL , GxB_LAND_LOR_BOOL , GxB_LXOR_LOR_BOOL , GxB_EQ_LOR_BOOL , GxB_ANY_LOR_BOOL , + GxB_LOR_LAND_BOOL , GxB_LAND_LAND_BOOL , GxB_LXOR_LAND_BOOL , GxB_EQ_LAND_BOOL , GxB_ANY_LAND_BOOL , + GxB_LOR_LXOR_BOOL , GxB_LAND_LXOR_BOOL , GxB_LXOR_LXOR_BOOL , GxB_EQ_LXOR_BOOL , GxB_ANY_LXOR_BOOL , + GxB_LOR_EQ_BOOL , GxB_LAND_EQ_BOOL , GxB_LXOR_EQ_BOOL , GxB_EQ_EQ_BOOL , GxB_ANY_EQ_BOOL , + GxB_LOR_GT_BOOL , GxB_LAND_GT_BOOL , GxB_LXOR_GT_BOOL , GxB_EQ_GT_BOOL , GxB_ANY_GT_BOOL , + GxB_LOR_LT_BOOL , GxB_LAND_LT_BOOL , GxB_LXOR_LT_BOOL , GxB_EQ_LT_BOOL , GxB_ANY_LT_BOOL , + GxB_LOR_GE_BOOL , GxB_LAND_GE_BOOL , GxB_LXOR_GE_BOOL , GxB_EQ_GE_BOOL , GxB_ANY_GE_BOOL , + GxB_LOR_LE_BOOL , GxB_LAND_LE_BOOL , GxB_LXOR_LE_BOOL , GxB_EQ_LE_BOOL , GxB_ANY_LE_BOOL , + +//------------------------------------------------------------------------------ +// 54 complex semirings +//------------------------------------------------------------------------------ + + // 3 monoids (plus, times, any), 2 types (FC32 and FC64), and 9 + // multiplicative operators. This list is not exhaustive, since it is + // possible to build complex semirings POW, ANY, ISEQ, and ISNE as the + // multiplicative operators. + + // Note that times_pair is identical to any_pair. + // These 2 are marked below. + + GxB_PLUS_FIRST_FC32 , GxB_TIMES_FIRST_FC32 , GxB_ANY_FIRST_FC32 , + GxB_PLUS_FIRST_FC64 , GxB_TIMES_FIRST_FC64 , GxB_ANY_FIRST_FC64 , + + GxB_PLUS_SECOND_FC32 , GxB_TIMES_SECOND_FC32 , GxB_ANY_SECOND_FC32 , + GxB_PLUS_SECOND_FC64 , GxB_TIMES_SECOND_FC64 , GxB_ANY_SECOND_FC64 , + + GxB_PLUS_PAIR_FC32 , GxB_TIMES_PAIR_FC32/**/, GxB_ANY_PAIR_FC32 , + GxB_PLUS_PAIR_FC64 , GxB_TIMES_PAIR_FC64/**/, GxB_ANY_PAIR_FC64 , + + GxB_PLUS_PLUS_FC32 , GxB_TIMES_PLUS_FC32 , GxB_ANY_PLUS_FC32 , + GxB_PLUS_PLUS_FC64 , GxB_TIMES_PLUS_FC64 , GxB_ANY_PLUS_FC64 , + + GxB_PLUS_MINUS_FC32 , GxB_TIMES_MINUS_FC32 , GxB_ANY_MINUS_FC32 , + GxB_PLUS_MINUS_FC64 , GxB_TIMES_MINUS_FC64 , GxB_ANY_MINUS_FC64 , + + GxB_PLUS_TIMES_FC32 , GxB_TIMES_TIMES_FC32 , GxB_ANY_TIMES_FC32 , + GxB_PLUS_TIMES_FC64 , GxB_TIMES_TIMES_FC64 , GxB_ANY_TIMES_FC64 , + + GxB_PLUS_DIV_FC32 , GxB_TIMES_DIV_FC32 , GxB_ANY_DIV_FC32 , + GxB_PLUS_DIV_FC64 , GxB_TIMES_DIV_FC64 , GxB_ANY_DIV_FC64 , + + GxB_PLUS_RDIV_FC32 , GxB_TIMES_RDIV_FC32 , GxB_ANY_RDIV_FC32 , + GxB_PLUS_RDIV_FC64 , GxB_TIMES_RDIV_FC64 , GxB_ANY_RDIV_FC64 , + + GxB_PLUS_RMINUS_FC32 , GxB_TIMES_RMINUS_FC32 , GxB_ANY_RMINUS_FC32 , + GxB_PLUS_RMINUS_FC64 , GxB_TIMES_RMINUS_FC64 , GxB_ANY_RMINUS_FC64 , + +//------------------------------------------------------------------------------ +// 64 bitwise semirings +//------------------------------------------------------------------------------ + + // monoids: (BOR, BAND, BXOR, BXNOR) x + // mult: (BOR, BAND, BXOR, BXNOR) x + // types: (UINT8, UINT16, UINT32, UINT64) + + // Many other bitwise semirings can be constructed using predefined types + // and operators. Bitwise monoids can be constructed for signed integer + // types, but these are not well-defined by the ANSI C specification, so + // they are excluded from the pre-defined monoids in SuiteSparse:GraphBLAS. + // Additional semirings can also be constructed with a multiplicative + // binary operator on any signed or unsigned integer type, as well. + + GxB_BOR_BOR_UINT8 , GxB_BOR_BOR_UINT16 , GxB_BOR_BOR_UINT32 , GxB_BOR_BOR_UINT64 , + GxB_BOR_BAND_UINT8 , GxB_BOR_BAND_UINT16 , GxB_BOR_BAND_UINT32 , GxB_BOR_BAND_UINT64 , + GxB_BOR_BXOR_UINT8 , GxB_BOR_BXOR_UINT16 , GxB_BOR_BXOR_UINT32 , GxB_BOR_BXOR_UINT64 , + GxB_BOR_BXNOR_UINT8 , GxB_BOR_BXNOR_UINT16 , GxB_BOR_BXNOR_UINT32 , GxB_BOR_BXNOR_UINT64 , + + GxB_BAND_BOR_UINT8 , GxB_BAND_BOR_UINT16 , GxB_BAND_BOR_UINT32 , GxB_BAND_BOR_UINT64 , + GxB_BAND_BAND_UINT8 , GxB_BAND_BAND_UINT16 , GxB_BAND_BAND_UINT32 , GxB_BAND_BAND_UINT64 , + GxB_BAND_BXOR_UINT8 , GxB_BAND_BXOR_UINT16 , GxB_BAND_BXOR_UINT32 , GxB_BAND_BXOR_UINT64 , + GxB_BAND_BXNOR_UINT8 , GxB_BAND_BXNOR_UINT16 , GxB_BAND_BXNOR_UINT32 , GxB_BAND_BXNOR_UINT64 , + + GxB_BXOR_BOR_UINT8 , GxB_BXOR_BOR_UINT16 , GxB_BXOR_BOR_UINT32 , GxB_BXOR_BOR_UINT64 , + GxB_BXOR_BAND_UINT8 , GxB_BXOR_BAND_UINT16 , GxB_BXOR_BAND_UINT32 , GxB_BXOR_BAND_UINT64 , + GxB_BXOR_BXOR_UINT8 , GxB_BXOR_BXOR_UINT16 , GxB_BXOR_BXOR_UINT32 , GxB_BXOR_BXOR_UINT64 , + GxB_BXOR_BXNOR_UINT8 , GxB_BXOR_BXNOR_UINT16 , GxB_BXOR_BXNOR_UINT32 , GxB_BXOR_BXNOR_UINT64 , + + GxB_BXNOR_BOR_UINT8 , GxB_BXNOR_BOR_UINT16 , GxB_BXNOR_BOR_UINT32 , GxB_BXNOR_BOR_UINT64 , + GxB_BXNOR_BAND_UINT8 , GxB_BXNOR_BAND_UINT16 , GxB_BXNOR_BAND_UINT32 , GxB_BXNOR_BAND_UINT64 , + GxB_BXNOR_BXOR_UINT8 , GxB_BXNOR_BXOR_UINT16 , GxB_BXNOR_BXOR_UINT32 , GxB_BXNOR_BXOR_UINT64 , + GxB_BXNOR_BXNOR_UINT8 , GxB_BXNOR_BXNOR_UINT16 , GxB_BXNOR_BXNOR_UINT32 , GxB_BXNOR_BXNOR_UINT64 ; + +//------------------------------------------------------------------------------ +// GrB_* semirings in the specification +//------------------------------------------------------------------------------ + +// The v1.3 C API for GraphBLAS adds the following 124 predefined semirings, +// with GrB* names. They are identical to 124 GxB* semirings defined above, +// with the same name, except that GrB_LXNOR_LOR_SEMIRING_BOOL is identical to +// GxB_EQ_LOR_BOOL (since GrB_EQ_BOOL == GrB_LXNOR). The old names are listed +// below alongside each new name; the new names are preferred. + +// 12 kinds of GrB* semirings are available for all 10 real, non-boolean types: + + // PLUS_TIMES, PLUS_MIN, + // MIN_PLUS, MIN_TIMES, MIN_FIRST, MIN_SECOND, MIN_MAX, + // MAX_PLUS, MAX_TIMES, MAX_FIRST, MAX_SECOND, MAX_MIN + +// and 4 semirings for boolean only: + + // LOR_LAND, LAND_LOR, LXOR_LAND, LXNOR_LOR. + +GB_PUBLIC GrB_Semiring + + //-------------------------------------------------------------------------- + // 20 semirings with PLUS monoids + //-------------------------------------------------------------------------- + + // PLUS_TIMES semirings for all 10 real, non-boolean types: + GrB_PLUS_TIMES_SEMIRING_INT8, // GxB_PLUS_TIMES_INT8 + GrB_PLUS_TIMES_SEMIRING_INT16, // GxB_PLUS_TIMES_INT16 + GrB_PLUS_TIMES_SEMIRING_INT32, // GxB_PLUS_TIMES_INT32 + GrB_PLUS_TIMES_SEMIRING_INT64, // GxB_PLUS_TIMES_INT64 + GrB_PLUS_TIMES_SEMIRING_UINT8, // GxB_PLUS_TIMES_UINT8 + GrB_PLUS_TIMES_SEMIRING_UINT16, // GxB_PLUS_TIMES_UINT16 + GrB_PLUS_TIMES_SEMIRING_UINT32, // GxB_PLUS_TIMES_UINT32 + GrB_PLUS_TIMES_SEMIRING_UINT64, // GxB_PLUS_TIMES_UINT64 + GrB_PLUS_TIMES_SEMIRING_FP32, // GxB_PLUS_TIMES_FP32 + GrB_PLUS_TIMES_SEMIRING_FP64, // GxB_PLUS_TIMES_FP64 + + // PLUS_MIN semirings for all 10 real, non-boolean types: + GrB_PLUS_MIN_SEMIRING_INT8, // GxB_PLUS_MIN_INT8 + GrB_PLUS_MIN_SEMIRING_INT16, // GxB_PLUS_MIN_INT16 + GrB_PLUS_MIN_SEMIRING_INT32, // GxB_PLUS_MIN_INT32 + GrB_PLUS_MIN_SEMIRING_INT64, // GxB_PLUS_MIN_INT64 + GrB_PLUS_MIN_SEMIRING_UINT8, // GxB_PLUS_MIN_UINT8 + GrB_PLUS_MIN_SEMIRING_UINT16, // GxB_PLUS_MIN_UINT16 + GrB_PLUS_MIN_SEMIRING_UINT32, // GxB_PLUS_MIN_UINT32 + GrB_PLUS_MIN_SEMIRING_UINT64, // GxB_PLUS_MIN_UINT64 + GrB_PLUS_MIN_SEMIRING_FP32, // GxB_PLUS_MIN_FP32 + GrB_PLUS_MIN_SEMIRING_FP64, // GxB_PLUS_MIN_FP64 + + //-------------------------------------------------------------------------- + // 50 semirings with MIN monoids + //-------------------------------------------------------------------------- + + // MIN_PLUS semirings for all 10 real, non-boolean types: + GrB_MIN_PLUS_SEMIRING_INT8, // GxB_MIN_PLUS_INT8 + GrB_MIN_PLUS_SEMIRING_INT16, // GxB_MIN_PLUS_INT16 + GrB_MIN_PLUS_SEMIRING_INT32, // GxB_MIN_PLUS_INT32 + GrB_MIN_PLUS_SEMIRING_INT64, // GxB_MIN_PLUS_INT64 + GrB_MIN_PLUS_SEMIRING_UINT8, // GxB_MIN_PLUS_UINT8 + GrB_MIN_PLUS_SEMIRING_UINT16, // GxB_MIN_PLUS_UINT16 + GrB_MIN_PLUS_SEMIRING_UINT32, // GxB_MIN_PLUS_UINT32 + GrB_MIN_PLUS_SEMIRING_UINT64, // GxB_MIN_PLUS_UINT64 + GrB_MIN_PLUS_SEMIRING_FP32, // GxB_MIN_PLUS_FP32 + GrB_MIN_PLUS_SEMIRING_FP64, // GxB_MIN_PLUS_FP64 + + // MIN_TIMES semirings for all 10 real, non-boolean types: + GrB_MIN_TIMES_SEMIRING_INT8, // GxB_MIN_TIMES_INT8 + GrB_MIN_TIMES_SEMIRING_INT16, // GxB_MIN_TIMES_INT16 + GrB_MIN_TIMES_SEMIRING_INT32, // GxB_MIN_TIMES_INT32 + GrB_MIN_TIMES_SEMIRING_INT64, // GxB_MIN_TIMES_INT64 + GrB_MIN_TIMES_SEMIRING_UINT8, // GxB_MIN_TIMES_UINT8 + GrB_MIN_TIMES_SEMIRING_UINT16, // GxB_MIN_TIMES_UINT16 + GrB_MIN_TIMES_SEMIRING_UINT32, // GxB_MIN_TIMES_UINT32 + GrB_MIN_TIMES_SEMIRING_UINT64, // GxB_MIN_TIMES_UINT64 + GrB_MIN_TIMES_SEMIRING_FP32, // GxB_MIN_TIMES_FP32 + GrB_MIN_TIMES_SEMIRING_FP64, // GxB_MIN_PLUS_FP64 + + // MIN_FIRST semirings for all 10 real, non-boolean types: + GrB_MIN_FIRST_SEMIRING_INT8, // GxB_MIN_FIRST_INT8 + GrB_MIN_FIRST_SEMIRING_INT16, // GxB_MIN_FIRST_INT16 + GrB_MIN_FIRST_SEMIRING_INT32, // GxB_MIN_FIRST_INT32 + GrB_MIN_FIRST_SEMIRING_INT64, // GxB_MIN_FIRST_INT64 + GrB_MIN_FIRST_SEMIRING_UINT8, // GxB_MIN_FIRST_UINT8 + GrB_MIN_FIRST_SEMIRING_UINT16, // GxB_MIN_FIRST_UINT16 + GrB_MIN_FIRST_SEMIRING_UINT32, // GxB_MIN_FIRST_UINT32 + GrB_MIN_FIRST_SEMIRING_UINT64, // GxB_MIN_FIRST_UINT64 + GrB_MIN_FIRST_SEMIRING_FP32, // GxB_MIN_FIRST_FP32 + GrB_MIN_FIRST_SEMIRING_FP64, // GxB_MIN_FIRST_FP64 + + // MIN_SECOND semirings for all 10 real, non-boolean types: + GrB_MIN_SECOND_SEMIRING_INT8, // GxB_MIN_SECOND_INT8 + GrB_MIN_SECOND_SEMIRING_INT16, // GxB_MIN_SECOND_INT16 + GrB_MIN_SECOND_SEMIRING_INT32, // GxB_MIN_SECOND_INT32 + GrB_MIN_SECOND_SEMIRING_INT64, // GxB_MIN_SECOND_INT64 + GrB_MIN_SECOND_SEMIRING_UINT8, // GxB_MIN_SECOND_UINT8 + GrB_MIN_SECOND_SEMIRING_UINT16, // GxB_MIN_SECOND_UINT16 + GrB_MIN_SECOND_SEMIRING_UINT32, // GxB_MIN_SECOND_UINT32 + GrB_MIN_SECOND_SEMIRING_UINT64, // GxB_MIN_SECOND_UINT64 + GrB_MIN_SECOND_SEMIRING_FP32, // GxB_MIN_SECOND_FP32 + GrB_MIN_SECOND_SEMIRING_FP64, // GxB_MIN_SECOND_FP64 + + // MIN_MAX semirings for all 10 real, non-boolean types: + GrB_MIN_MAX_SEMIRING_INT8, // GxB_MIN_MAX_INT8 + GrB_MIN_MAX_SEMIRING_INT16, // GxB_MIN_MAX_INT16 + GrB_MIN_MAX_SEMIRING_INT32, // GxB_MIN_MAX_INT32 + GrB_MIN_MAX_SEMIRING_INT64, // GxB_MIN_MAX_INT64 + GrB_MIN_MAX_SEMIRING_UINT8, // GxB_MIN_MAX_UINT8 + GrB_MIN_MAX_SEMIRING_UINT16, // GxB_MIN_MAX_UINT16 + GrB_MIN_MAX_SEMIRING_UINT32, // GxB_MIN_MAX_UINT32 + GrB_MIN_MAX_SEMIRING_UINT64, // GxB_MIN_MAX_UINT64 + GrB_MIN_MAX_SEMIRING_FP32, // GxB_MIN_MAX_FP32 + GrB_MIN_MAX_SEMIRING_FP64, // GxB_MIN_MAX_FP64 + + //-------------------------------------------------------------------------- + // 50 semirings with MAX monoids + //-------------------------------------------------------------------------- + + // MAX_PLUS semirings for all 10 real, non-boolean types + GrB_MAX_PLUS_SEMIRING_INT8, // GxB_MAX_PLUS_INT8 + GrB_MAX_PLUS_SEMIRING_INT16, // GxB_MAX_PLUS_INT16 + GrB_MAX_PLUS_SEMIRING_INT32, // GxB_MAX_PLUS_INT32 + GrB_MAX_PLUS_SEMIRING_INT64, // GxB_MAX_PLUS_INT64 + GrB_MAX_PLUS_SEMIRING_UINT8, // GxB_MAX_PLUS_UINT8 + GrB_MAX_PLUS_SEMIRING_UINT16, // GxB_MAX_PLUS_UINT16 + GrB_MAX_PLUS_SEMIRING_UINT32, // GxB_MAX_PLUS_UINT32 + GrB_MAX_PLUS_SEMIRING_UINT64, // GxB_MAX_PLUS_UINT64 + GrB_MAX_PLUS_SEMIRING_FP32, // GxB_MAX_PLUS_FP32 + GrB_MAX_PLUS_SEMIRING_FP64, // GxB_MAX_PLUS_FP64 + + // MAX_TIMES semirings for all 10 real, non-boolean types: + GrB_MAX_TIMES_SEMIRING_INT8, // GxB_MAX_TIMES_INT8 + GrB_MAX_TIMES_SEMIRING_INT16, // GxB_MAX_TIMES_INT16 + GrB_MAX_TIMES_SEMIRING_INT32, // GxB_MAX_TIMES_INT32 + GrB_MAX_TIMES_SEMIRING_INT64, // GxB_MAX_TIMES_INT64 + GrB_MAX_TIMES_SEMIRING_UINT8, // GxB_MAX_TIMES_UINT8 + GrB_MAX_TIMES_SEMIRING_UINT16, // GxB_MAX_TIMES_UINT16 + GrB_MAX_TIMES_SEMIRING_UINT32, // GxB_MAX_TIMES_UINT32 + GrB_MAX_TIMES_SEMIRING_UINT64, // GxB_MAX_TIMES_UINT64 + GrB_MAX_TIMES_SEMIRING_FP32, // GxB_MAX_TIMES_FP32 + GrB_MAX_TIMES_SEMIRING_FP64, // GxB_MAX_TIMES_FP64 + + // MAX_FIRST semirings for all 10 real, non-boolean types: + GrB_MAX_FIRST_SEMIRING_INT8, // GxB_MAX_FIRST_INT8 + GrB_MAX_FIRST_SEMIRING_INT16, // GxB_MAX_FIRST_INT16 + GrB_MAX_FIRST_SEMIRING_INT32, // GxB_MAX_FIRST_INT32 + GrB_MAX_FIRST_SEMIRING_INT64, // GxB_MAX_FIRST_INT64 + GrB_MAX_FIRST_SEMIRING_UINT8, // GxB_MAX_FIRST_UINT8 + GrB_MAX_FIRST_SEMIRING_UINT16, // GxB_MAX_FIRST_UINT16 + GrB_MAX_FIRST_SEMIRING_UINT32, // GxB_MAX_FIRST_UINT32 + GrB_MAX_FIRST_SEMIRING_UINT64, // GxB_MAX_FIRST_UINT64 + GrB_MAX_FIRST_SEMIRING_FP32, // GxB_MAX_FIRST_FP32 + GrB_MAX_FIRST_SEMIRING_FP64, // GxB_MAX_FIRST_FP64 + + // MAX_SECOND semirings for all 10 real, non-boolean types: + GrB_MAX_SECOND_SEMIRING_INT8, // GxB_MAX_SECOND_INT8 + GrB_MAX_SECOND_SEMIRING_INT16, // GxB_MAX_SECOND_INT16 + GrB_MAX_SECOND_SEMIRING_INT32, // GxB_MAX_SECOND_INT32 + GrB_MAX_SECOND_SEMIRING_INT64, // GxB_MAX_SECOND_INT64 + GrB_MAX_SECOND_SEMIRING_UINT8, // GxB_MAX_SECOND_UINT8 + GrB_MAX_SECOND_SEMIRING_UINT16, // GxB_MAX_SECOND_UINT16 + GrB_MAX_SECOND_SEMIRING_UINT32, // GxB_MAX_SECOND_UINT32 + GrB_MAX_SECOND_SEMIRING_UINT64, // GxB_MAX_SECOND_UINT64 + GrB_MAX_SECOND_SEMIRING_FP32, // GxB_MAX_SECOND_FP32 + GrB_MAX_SECOND_SEMIRING_FP64, // GxB_MAX_SECOND_FP64 + + // MAX_MIN semirings for all 10 real, non-boolean types: + GrB_MAX_MIN_SEMIRING_INT8, // GxB_MAX_MIN_INT8 + GrB_MAX_MIN_SEMIRING_INT16, // GxB_MAX_MIN_INT16 + GrB_MAX_MIN_SEMIRING_INT32, // GxB_MAX_MIN_INT32 + GrB_MAX_MIN_SEMIRING_INT64, // GxB_MAX_MIN_INT64 + GrB_MAX_MIN_SEMIRING_UINT8, // GxB_MAX_MIN_UINT8 + GrB_MAX_MIN_SEMIRING_UINT16, // GxB_MAX_MIN_UINT16 + GrB_MAX_MIN_SEMIRING_UINT32, // GxB_MAX_MIN_UINT32 + GrB_MAX_MIN_SEMIRING_UINT64, // GxB_MAX_MIN_UINT64 + GrB_MAX_MIN_SEMIRING_FP32, // GxB_MAX_MIN_FP32 + GrB_MAX_MIN_SEMIRING_FP64, // GxB_MAX_MIN_FP64 + + //-------------------------------------------------------------------------- + // 4 boolean semirings: + //-------------------------------------------------------------------------- + GrB_LOR_LAND_SEMIRING_BOOL, // GxB_LOR_LAND_BOOL + GrB_LAND_LOR_SEMIRING_BOOL, // GxB_LAND_LOR_BOOL + GrB_LXOR_LAND_SEMIRING_BOOL, // GxB_LXOR_LAND_BOOL + GrB_LXNOR_LOR_SEMIRING_BOOL ; // GxB_EQ_LOR_BOOL (note EQ == LXNOR) //------------------------------------------------------------------------------ -// GxB_resize: change the size of a matrix or vector +// GrB_*_resize: change the size of a matrix or vector //------------------------------------------------------------------------------ // If the dimensions decrease, entries that fall outside the resized matrix or -// vector are deleted +// vector are deleted. GrB_Matrix_resize and GrB_Vector_resize now appear in +// the spec, with the identical behaviour as the earlier GxB_*_resize +// functions. The Generic GxB_resize does not appear in the spec. The old +// GxB* names are kept for backward compatibility, but new code should use +// the GrB* names. + +GB_PUBLIC +GrB_Info GrB_Matrix_resize // change the size of a matrix +( + GrB_Matrix A, // matrix to modify + GrB_Index nrows_new, // new number of rows in matrix + GrB_Index ncols_new // new number of columns in matrix +) ; + +GB_PUBLIC +GrB_Info GrB_Vector_resize // change the size of a vector +( + GrB_Vector u, // vector to modify + GrB_Index nrows_new // new number of rows in vector +) ; GB_PUBLIC GrB_Info GxB_Matrix_resize // change the size of a matrix @@ -6449,7 +8181,7 @@ GrB_Info GxB_Vector_resize // change the size of a vector GrB_Index nrows_new // new number of rows in vector ) ; -// GxB_resize is a generic function for resizing a matrix or vector +// GxB_resize is a generic function for resizing a matrix or vector: // GrB_Vector_resize (u,nrows_new) // GrB_Matrix_resize (A,nrows_new,ncols_new) @@ -6459,16 +8191,21 @@ GrB_Info GxB_Vector_resize // change the size of a vector _Generic \ ( \ (arg1), \ - GrB_Vector : GxB_Vector_resize , \ - GrB_Matrix : GxB_Matrix_resize \ + GrB_Vector : GrB_Vector_resize , \ + GrB_Matrix : GrB_Matrix_resize \ ) \ (arg1, __VA_ARGS__) #endif //------------------------------------------------------------------------------ -// GxB_kron: Kronecker product +// GrB_kronecker: Kronecker product //------------------------------------------------------------------------------ +// GxB_kron is now called GrB_Matrix_kronecker_BinaryOp, and can also be used +// by the generic GrB_kronecker. The GxB_kron name is kept for backward +// compatibility. GxB_kron will be kept for backward compatibility, but +// new user code should switch to GrB_kronecker. + GB_PUBLIC GrB_Info GxB_kron // C = accum (C, kron(A,B)) ( @@ -6481,6 +8218,57 @@ GrB_Info GxB_kron // C = accum (C, kron(A,B)) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; +GB_PUBLIC +GrB_Info GrB_Matrix_kronecker_BinaryOp // C = accum (C, kron(A,B)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix M, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // defines '*' for T=kron(A,B) + const GrB_Matrix A, // first input: matrix A + const GrB_Matrix B, // second input: matrix B + const GrB_Descriptor desc // descriptor for C, M, A, and B +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_kronecker_Monoid // C = accum (C, kron(A,B)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix M, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_Monoid monoid, // defines '*' for T=kron(A,B) + const GrB_Matrix A, // first input: matrix A + const GrB_Matrix B, // second input: matrix B + const GrB_Descriptor desc // descriptor for C, M, A, and B +) ; + +GB_PUBLIC +GrB_Info GrB_Matrix_kronecker_Semiring // C = accum (C, kron(A,B)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix M, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_Semiring semiring, // defines '*' for T=kron(A,B) + const GrB_Matrix A, // first input: matrix A + const GrB_Matrix B, // second input: matrix B + const GrB_Descriptor desc // descriptor for C, M, A, and B +) ; + +#if GxB_STDC_VERSION >= 201112L +#define GrB_kronecker(C,Mask,accum,op,A,B,desc) \ + _Generic \ + ( \ + (op), \ + const GrB_Semiring : GrB_Matrix_kronecker_Semiring , \ + GrB_Semiring : GrB_Matrix_kronecker_Semiring , \ + const GrB_Monoid : GrB_Matrix_kronecker_Monoid , \ + GrB_Monoid : GrB_Matrix_kronecker_Monoid , \ + const GrB_BinaryOp : GrB_Matrix_kronecker_BinaryOp , \ + GrB_BinaryOp : GrB_Matrix_kronecker_BinaryOp \ + ) \ + (C, Mask, accum, op, A, B, desc) +#endif + //------------------------------------------------------------------------------ // GxB_fprint and GxB_print: print the contents of a GraphBLAS object //------------------------------------------------------------------------------ @@ -6531,7 +8319,9 @@ typedef enum GxB_SILENT = 0, // nothing is printed, just check the object GxB_SUMMARY = 1, // print a terse summary GxB_SHORT = 2, // short description, about 30 entries of a matrix - GxB_COMPLETE = 3 // print the entire contents of the object + GxB_COMPLETE = 3, // print the entire contents of the object + GxB_SHORT_VERBOSE = 4, // GxB_SHORT but with "%.15g" for doubles + GxB_COMPLETE_VERBOSE = 5 // GxB_COMPLETE but with "%.15g" for doubles } GxB_Print_Level ; @@ -7049,5 +8839,45 @@ GrB_Info GxB_Vector_export // export and free a vector // first reformats the GrB_Matrix A into the desired format, and then exports // the result. +//------------------------------------------------------------------------------ +// CUDA memory management (DRAFT: in progress, do not use) +//------------------------------------------------------------------------------ + +// These functions are made available to the user application, since the +// GxB_import/export functions require the user application and the GraphBLAS +// library to rely on the same malloc/calloc/realloc/free functions. If +// GraphBLAS is using CUDA Unified Memory Management and GxB_cuda_init is used +// to initialize GraphBLAS, then all of its memory allocations rely on these +// functions. + +// If GraphBLAS is compiled with CUDA enabled, these functions map to +// cudaMallocManaged and cudaFree. Otherwise, they map to the ANSI C malloc, +// calloc, and free functions. + +// Note that there is no cudaReallocManaged function, and in this case +// GraphBLAS makes do without it. As a result, the user application cannot use +// realloc either, for memory blocks passed to/from GraphBLAS via +// import/export. + +void *GxB_cuda_malloc (size_t size) ; // standard malloc signature +void *GxB_cuda_calloc (size_t n, size_t size) ; // standard calloc signature +void GxB_cuda_free (void *p) ; // standard free signature + +//------------------------------------------------------------------------------ +// MKL optimization (DRAFT: in progress, do not use) +//------------------------------------------------------------------------------ + +GrB_Info GxB_mxv_optimize // analyze A for subsequent use in mxv +( + GrB_Matrix A, // input/output matrix + int64_t ncalls, // estimate # of future calls to GrB_mxv + const GrB_Descriptor desc // currently unused +) ; + +GrB_Info GxB_mxv_optimize_free // analyze A for subsequent use in mxv +( + GrB_Matrix A // input/output matrix +) ; + #endif diff --git a/Config/README.md.in b/Config/README.md.in index ddc86add93..fb93a4bd73 100644 --- a/Config/README.md.in +++ b/Config/README.md.in @@ -19,8 +19,9 @@ applications. See http://graphblas.org for more information on GraphBLAS, including the GraphBLAS C API (also in `Doc/GraphBLAS_API_C.pdf`). See -https://github.com/szarnyasg/graphblas-pointers for additional resources on -GraphBLAS. +https://github.com/GraphBLAS/GraphBLAS-Pointers +for additional resources on GraphBLAS. + QUICK START: To compile, run several demos, and install, do these commands in this directory: diff --git a/Demo/InProgress/gpu_reduce_demo.c b/Demo/InProgress/gpu_reduce_demo.c new file mode 100644 index 0000000000..1d35778cc7 --- /dev/null +++ b/Demo/InProgress/gpu_reduce_demo.c @@ -0,0 +1,121 @@ +//------------------------------------------------------------------------------ +// GraphBLAS/Demo/Program/reduce_demo: reduce a matrix to a scalar +//------------------------------------------------------------------------------ + +// TODO for GPU: add this to CMakelists.txt, or merge with reduce_demo.c + +#include "GraphBLAS.h" + +// #define N 65536 + #define N 16384 + +int main (void) +{ + + #if defined ( _OPENMP ) + double t0 = omp_get_wtime ( ) ; + #endif + + // start GraphBLAS + GrB_init (GrB_NONBLOCKING) ; + printf ("demo: reduce a matrix to a scalar\n") ; + + int nthreads_max ; + GxB_get (GxB_NTHREADS, &nthreads_max) ; + printf ("# of threads: %d\n", nthreads_max) ; + + #if defined ( _OPENMP ) + t0 = omp_get_wtime ( ) - t0 ; + printf ("GPU warmup time: %g\n", t0) ; + t0 = omp_get_wtime ( ) ; + #endif + + GrB_Index nrows = N ; + GrB_Index ncols = N ; + GrB_Matrix A ; + GrB_Matrix_new (&A, GrB_INT64, nrows, ncols) ; + + GrB_Index *I = malloc (nrows * ncols * sizeof (GrB_Index)) ; + GrB_Index *J = malloc (nrows * ncols * sizeof (GrB_Index)) ; + int64_t *X = malloc (nrows * ncols * sizeof (int64_t)) ; + + #pragma omp parallel for num_threads(nthreads_max) collapse(2) \ + schedule(static) + for (int64_t i = 0 ; i < nrows ; i++) + { + for (int64_t j = 0 ; j < ncols ; j++) + { + int64_t k = i * N + j ; + // int x = (int) (rand ( ) & 0xFF) ; + int x = (int) (k & 0xFF) ; + I [k] = i ; + J [k] = j ; + X [k] = x ; + } + } + + GrB_Index nvals = ((size_t) N) * ((size_t) N) ; + GrB_Matrix_build (A, I, J, X, nvals, GrB_PLUS_INT64) ; + + GxB_print (A, 2) ; + + free (I) ; + free (J) ; + free (X) ; + + #if defined ( _OPENMP ) + t0 = omp_get_wtime ( ) - t0 ; + printf ("time to create matrix: %g\n", t0) ; + #endif + + GrB_Index result ; + + GrB_Matrix B ; + GrB_Matrix_new (&B, GrB_INT64, 2000, 2000) ; + for (int64_t i = 0 ; i < 2000 ; i++) + { + for (int64_t j = 0 ; j < 2000 ; j++) + { + GrB_Matrix_setElement (B, 1, i, j) ; + } + } + GrB_Index ignore ; + GrB_Matrix_nvals (&ignore, B) ; + + #if defined ( _OPENMP ) + double tfirst = omp_get_wtime ( ) ; + #endif + GrB_reduce (&result, NULL, GxB_PLUS_INT64_MONOID, B, NULL) ; + #if defined ( _OPENMP ) + tfirst = omp_get_wtime ( ) - tfirst ; + printf ("warmup %g sec (on all threads/gpu, small matrix)\n", tfirst) ; + printf ("result: %"PRIu64"\n", result) ; + #endif + + double t1 ; + + printf ("\nreduce to a scalar:\n") ; + + for (int nthreads = 1 ; nthreads <= nthreads_max ; nthreads++) + { + GxB_set (GxB_NTHREADS, nthreads) ; + #if defined ( _OPENMP ) + double t = omp_get_wtime ( ) ; + #endif + GrB_reduce (&result, NULL, GxB_PLUS_INT64_MONOID, A, NULL) ; + #if defined ( _OPENMP ) + t = omp_get_wtime ( ) - t ; + if (nthreads == 1) t1 = t ; + printf ("nthreads %3d time: %12.6f speedup %8.2f\n", + nthreads, t, t1/t) ; + #endif + } + + // printf ("result %d\n", result) ; + printf ("result %"PRId64"\n", (int64_t) result) ; + + // free everyting + GrB_free (&A) ; + GrB_finalize ( ) ; +} + diff --git a/Demo/Include/graphblas_demos.h b/Demo/Include/graphblas_demos.h index 39ed63ddd0..9b5fd4e9b5 100644 --- a/Demo/Include/graphblas_demos.h +++ b/Demo/Include/graphblas_demos.h @@ -19,7 +19,11 @@ #elif defined __GNUC__ #pragma GCC diagnostic ignored "-Wunknown-pragmas" -#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#if !defined ( __cplusplus ) +#pragma GCC diagnostic ignored "-Wincompatible-pointer-types" +#else +#pragma GCC diagnostic ignored "-Wwrite-strings" +#endif #pragma GCC diagnostic ignored "-Wformat-truncation=" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-result" @@ -27,7 +31,6 @@ #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wtype-limits" -#pragma GCC diagnostic ignored "-Wincompatible-pointer-types" // enable these warnings as errors #pragma GCC diagnostic error "-Wmisleading-indentation" diff --git a/Demo/Include/usercomplex.h b/Demo/Include/usercomplex.h index f7b1643be1..51240de477 100644 --- a/Demo/Include/usercomplex.h +++ b/Demo/Include/usercomplex.h @@ -10,34 +10,6 @@ #ifndef USERCOMPLEX_H #define USERCOMPLEX_H -//------------------------------------------------------------------------------ -// ANSI C11 is required for the 'double complex' type -//------------------------------------------------------------------------------ - -// See the following link for complex math support in Microsoft Visual Studio: -// https://docs.microsoft.com/en-us/cpp/c-runtime-library/complex-math-support?view=vs-2019 -// The complex data type is not supported for this demo, when compiling with MS -// Visual Studio. - -// The GraphBLAS objects defined here are still visible if 'double complex' -// is not supported, but they are all NULL in that case. - -#if GxB_STDC_VERSION >= 201112L -#include -#endif - -// This macro is defined but cannot be used without ANSI C11: -#ifndef CMPLX -#define CMPLX(real,imag) \ - ( \ - (double complex)((double)(real)) + \ - (double complex)((double)(imag) * _Complex_I) \ - ) -#endif - -// "I" is used in GraphBLAS to denote a list of row indices; remove it here -#undef I - //------------------------------------------------------------------------------ // 10 binary functions, z=f(x,y), where CxC -> C //------------------------------------------------------------------------------ @@ -109,8 +81,87 @@ GB_PUBLIC GrB_UnaryOp Complex_complex_real, Complex_complex_imag ; GB_PUBLIC GrB_Type Complex ; GB_PUBLIC GrB_Monoid Complex_plus_monoid, Complex_times_monoid ; GB_PUBLIC GrB_Semiring Complex_plus_times ; -GB_PUBLIC GrB_Info Complex_init ( ) ; +GB_PUBLIC GrB_Info Complex_init (bool builtin_complex) ; GB_PUBLIC GrB_Info Complex_finalize ( ) ; +//------------------------------------------------------------------------------ +// C++ compatibility +//------------------------------------------------------------------------------ + +#if defined ( __cplusplus ) + + using namespace std ; + + #define crealf(x) real(x) + #define creal(x) real(x) + #define cimagf(x) imag(x) + #define cimag(x) imag(x) + #define cpowf(x,y) pow(x,y) + #define cpow(x,y) pow(x,y) + #define powf(x,y) pow(x,y) + #define cexpf(x) exp(x) + #define cexp(x) exp(x) + #define expf(x) exp(x) + + #define clogf(x) log(x) + #define clog(x) log(x) + #define logf(x) log(x) + + #define cabsf(x) abs(x) + #define cabs(x) abs(x) + #define absf(x) abs(x) + + #define csqrtf(x) sqrt(x) + #define csqrt(x) sqrt(x) + #define sqrtf(x) sqrt(x) + + #define conjf(x) conj(x) + + #define cargf(x) arg(x) + #define carg(x) arg(x) + + #define csinf(x) sin(x) + #define csin(x) sin(x) + #define sinf(x) sin(x) + #define ccosf(x) cos(x) + #define ccos(x) cos(x) + #define cosf(x) cos(x) + #define ctanf(x) tan(x) + #define ctan(x) tan(x) + #define tanf(x) tan(x) + + #define casinf(x) asin(x) + #define casin(x) asin(x) + #define asinf(x) asin(x) + #define cacosf(x) acos(x) + #define cacos(x) acos(x) + #define acosf(x) acos(x) + #define catanf(x) atan(x) + #define catan(x) atan(x) + #define atanf(x) atan(x) + + #define csinhf(x) sinh(x) + #define csinh(x) sinh(x) + #define sinhf(x) sinh(x) + #define ccoshf(x) cosh(x) + #define ccosh(x) cosh(x) + #define coshf(x) cosh(x) + #define ctanhf(x) tanh(x) + #define ctanh(x) tanh(x) + #define tanhf(x) tanh(x) + + #define casinhf(x) asinh(x) + #define casinh(x) asinh(x) + #define asinhf(x) asinh(x) + #define cacoshf(x) acosh(x) + #define cacosh(x) acosh(x) + #define acoshf(x) acosh(x) + #define catanhf(x) atanh(x) + #define catanh(x) atanh(x) + #define atanhf(x) atanh(x) + +#endif + + #endif diff --git a/Demo/Output/tri_demo.out b/Demo/Output/tri_demo.out index 3aeaced60f..861568b782 100644 --- a/Demo/Output/tri_demo.out +++ b/Demo/Output/tri_demo.out @@ -1,293 +1,305 @@ -------------------------------------------------------------- Wathen: nx 4 ny 4 n 65 nz 752 method 0, time: 0.000 sec -total time to read A matrix: 0.000251 sec +total time to read A matrix: 0.000279 sec n 65 # edges 376 -U=triu(A) time: 0.000031 sec -L=tril(A) time: 0.000010 sec +U=triu(A) time: 0.000032 sec +L=tril(A) time: 0.000008 sec ------------------------------------- dot product method: # triangles 872 -L*U' time (dot): 0.000048 sec -tricount time: 0.000058 sec (dot product method) -tri+prep time: 0.000099 sec (incl time to compute L and U) -compute C time: 0.000048 sec -reduce (C) time: 0.000010 sec -rate 3.79 million edges/sec (incl time for U=triu(A)) -rate 6.47 million edges/sec (just tricount itself) -L*U' time (dot): 0.000014 sec (nthreads: 2 speedup 3.51141) -tricount time: 0.000018 sec (dot product method) +L*U' time (dot): 0.000055 sec +tricount time: 0.000071 sec (dot product method) +tri+prep time: 0.000111 sec (incl time to compute L and U) +compute C time: 0.000055 sec +reduce (C) time: 0.000016 sec +rate 3.39 million edges/sec (incl time for U=triu(A)) +rate 5.27 million edges/sec (just tricount itself) +L*U' time (dot): 0.000015 sec (nthreads: 2 speedup 3.70945) +tricount time: 0.000020 sec (dot product method) tri+prep time: 0.000059 sec (incl time to compute L and U) -compute C time: 0.000014 sec -reduce (C) time: 0.000004 sec -rate 6.36 million edges/sec (incl time for U=triu(A)) -rate 20.96 million edges/sec (just tricount itself) -L*U' time (dot): 0.000013 sec (nthreads: 4 speedup 3.66527) -tricount time: 0.000019 sec (dot product method) -tri+prep time: 0.000060 sec (incl time to compute L and U) -compute C time: 0.000013 sec -reduce (C) time: 0.000005 sec -rate 6.30 million edges/sec (incl time for U=triu(A)) -rate 20.32 million edges/sec (just tricount itself) -L*U' time (dot): 0.000015 sec (nthreads: 8 speedup 3.24119) -tricount time: 0.000019 sec (dot product method) -tri+prep time: 0.000060 sec (incl time to compute L and U) compute C time: 0.000015 sec +reduce (C) time: 0.000005 sec +rate 6.34 million edges/sec (incl time for U=triu(A)) +rate 19.13 million edges/sec (just tricount itself) +L*U' time (dot): 0.000013 sec (nthreads: 4 speedup 4.16316) +tricount time: 0.000017 sec (dot product method) +tri+prep time: 0.000057 sec (incl time to compute L and U) +compute C time: 0.000013 sec reduce (C) time: 0.000004 sec -rate 6.27 million edges/sec (incl time for U=triu(A)) -rate 20.03 million edges/sec (just tricount itself) -L*U' time (dot): 0.000019 sec -tricount time: 0.000025 sec (dot product method) -tri+prep time: 0.000067 sec (incl time to compute L and U) -compute C time: 0.000019 sec -reduce (C) time: 0.000006 sec -rate 5.65 million edges/sec (incl time for U=triu(A)) -rate 14.83 million edges/sec (just tricount itself) -L*U' time (dot): 0.000016 sec (nthreads: 2 speedup 1.23569) -tricount time: 0.000020 sec (dot product method) -tri+prep time: 0.000061 sec (incl time to compute L and U) -compute C time: 0.000016 sec +rate 6.58 million edges/sec (incl time for U=triu(A)) +rate 21.52 million edges/sec (just tricount itself) +L*U' time (dot): 0.000012 sec (nthreads: 8 speedup 4.43079) +tricount time: 0.000016 sec (dot product method) +tri+prep time: 0.000056 sec (incl time to compute L and U) +compute C time: 0.000012 sec reduce (C) time: 0.000004 sec -rate 6.18 million edges/sec (incl time for U=triu(A)) -rate 19.09 million edges/sec (just tricount itself) -L*U' time (dot): 0.000013 sec (nthreads: 4 speedup 1.4938) -tricount time: 0.000018 sec (dot product method) +rate 6.72 million edges/sec (incl time for U=triu(A)) +rate 23.04 million edges/sec (just tricount itself) +L*U' time (dot): 0.000016 sec +tricount time: 0.000021 sec (dot product method) tri+prep time: 0.000060 sec (incl time to compute L and U) +compute C time: 0.000016 sec +reduce (C) time: 0.000004 sec +rate 6.25 million edges/sec (incl time for U=triu(A)) +rate 18.32 million edges/sec (just tricount itself) +L*U' time (dot): 0.000013 sec (nthreads: 2 speedup 1.23168) +tricount time: 0.000017 sec (dot product method) +tri+prep time: 0.000057 sec (incl time to compute L and U) compute C time: 0.000013 sec -reduce (C) time: 0.000005 sec -rate 6.31 million edges/sec (incl time for U=triu(A)) -rate 20.46 million edges/sec (just tricount itself) -L*U' time (dot): 0.000015 sec (nthreads: 8 speedup 1.31382) -tricount time: 0.000019 sec (dot product method) -tri+prep time: 0.000060 sec (incl time to compute L and U) -compute C time: 0.000015 sec reduce (C) time: 0.000004 sec -rate 6.27 million edges/sec (incl time for U=triu(A)) -rate 20.06 million edges/sec (just tricount itself) +rate 6.65 million edges/sec (incl time for U=triu(A)) +rate 22.27 million edges/sec (just tricount itself) +L*U' time (dot): 0.000013 sec (nthreads: 4 speedup 1.27601) +tricount time: 0.000017 sec (dot product method) +tri+prep time: 0.000056 sec (incl time to compute L and U) +compute C time: 0.000013 sec +reduce (C) time: 0.000004 sec +rate 6.67 million edges/sec (incl time for U=triu(A)) +rate 22.52 million edges/sec (just tricount itself) +L*U' time (dot): 0.000012 sec (nthreads: 8 speedup 1.31332) +tricount time: 0.000016 sec (dot product method) +tri+prep time: 0.000056 sec (incl time to compute L and U) +compute C time: 0.000012 sec +reduce (C) time: 0.000004 sec +rate 6.77 million edges/sec (incl time for U=triu(A)) +rate 23.59 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000046 sec -tricount time: 0.000048 sec (saxpy method) -tri+prep time: 0.000058 sec (incl time to compute L) -compute C time: 0.000046 sec -reduce (C) time: 0.000002 sec -rate 6.51 million edges/sec (incl time for L=tril(A)) -rate 7.83 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000020 sec (nthreads: 2 speedup 2.36859) -tricount time: 0.000021 sec (saxpy method) +triangles, method 3: 872 +C=L*L time (saxpy): 0.000045 sec +tricount time: 0.000047 sec (saxpy method) +tri+prep time: 0.000055 sec (incl time to compute L) +compute C time: 0.000045 sec +reduce (C) time: 0.000001 sec +rate 6.88 million edges/sec (incl time for L=tril(A)) +rate 8.06 million edges/sec (just tricount itself) +triangles, method 3: 872 +C=L*L time (saxpy): 0.000021 sec (nthreads: 2 speedup 2.10986) +tricount time: 0.000023 sec (saxpy method) tri+prep time: 0.000031 sec (incl time to compute L) -compute C time: 0.000020 sec +compute C time: 0.000021 sec reduce (C) time: 0.000001 sec -rate 12.31 million edges/sec (incl time for L=tril(A)) -rate 18.09 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000019 sec (nthreads: 4 speedup 2.3942) -tricount time: 0.000021 sec (saxpy method) +rate 12.24 million edges/sec (incl time for L=tril(A)) +rate 16.56 million edges/sec (just tricount itself) +triangles, method 3: 872 +C=L*L time (saxpy): 0.000022 sec (nthreads: 4 speedup 2.06334) +tricount time: 0.000023 sec (saxpy method) tri+prep time: 0.000031 sec (incl time to compute L) +compute C time: 0.000022 sec +reduce (C) time: 0.000001 sec +rate 12.00 million edges/sec (incl time for L=tril(A)) +rate 16.12 million edges/sec (just tricount itself) +triangles, method 3: 872 +C=L*L time (saxpy): 0.000019 sec (nthreads: 8 speedup 2.35071) +tricount time: 0.000021 sec (saxpy method) +tri+prep time: 0.000029 sec (incl time to compute L) compute C time: 0.000019 sec -reduce (C) time: 0.000002 sec -rate 12.18 million edges/sec (incl time for L=tril(A)) -rate 17.80 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000025 sec (nthreads: 8 speedup 1.85853) -tricount time: 0.000026 sec (saxpy method) -tri+prep time: 0.000036 sec (incl time to compute L) -compute C time: 0.000025 sec reduce (C) time: 0.000001 sec -rate 10.40 million edges/sec (incl time for L=tril(A)) -rate 14.23 million edges/sec (just tricount itself) +rate 13.13 million edges/sec (incl time for L=tril(A)) +rate 18.22 million edges/sec (just tricount itself) -------------------------------------------------------------- random 5 by 5, nz: 18, method 1 time 0.000 sec -total time to read A matrix: 0.000102 sec +total time to read A matrix: 0.000128 sec n 5 # edges 9 -U=triu(A) time: 0.000035 sec -L=tril(A) time: 0.000005 sec +U=triu(A) time: 0.000041 sec +L=tril(A) time: 0.000006 sec ------------------------------------- dot product method: # triangles 7 -L*U' time (dot): 0.000035 sec -tricount time: 0.000043 sec (dot product method) -tri+prep time: 0.000084 sec (incl time to compute L and U) -compute C time: 0.000035 sec -reduce (C) time: 0.000008 sec -rate 0.11 million edges/sec (incl time for U=triu(A)) -rate 0.21 million edges/sec (just tricount itself) -L*U' time (dot): 0.000005 sec (nthreads: 2 speedup 6.64765) +L*U' time (dot): 0.000039 sec +tricount time: 0.000053 sec (dot product method) +tri+prep time: 0.000100 sec (incl time to compute L and U) +compute C time: 0.000039 sec +reduce (C) time: 0.000014 sec +rate 0.09 million edges/sec (incl time for U=triu(A)) +rate 0.17 million edges/sec (just tricount itself) +L*U' time (dot): 0.000005 sec (nthreads: 2 speedup 7.69034) tricount time: 0.000008 sec (dot product method) -tri+prep time: 0.000049 sec (incl time to compute L and U) -compute C time: 0.000005 sec -reduce (C) time: 0.000003 sec -rate 0.18 million edges/sec (incl time for U=triu(A)) -rate 1.12 million edges/sec (just tricount itself) -L*U' time (dot): 0.000005 sec (nthreads: 4 speedup 7.46184) -tricount time: 0.000007 sec (dot product method) -tri+prep time: 0.000048 sec (incl time to compute L and U) +tri+prep time: 0.000054 sec (incl time to compute L and U) compute C time: 0.000005 sec reduce (C) time: 0.000002 sec -rate 0.19 million edges/sec (incl time for U=triu(A)) -rate 1.33 million edges/sec (just tricount itself) -L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 13.0022) -tricount time: 0.000004 sec (dot product method) -tri+prep time: 0.000045 sec (incl time to compute L and U) +rate 0.17 million edges/sec (incl time for U=triu(A)) +rate 1.18 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 4 speedup 11.3518) +tricount time: 0.000006 sec (dot product method) +tri+prep time: 0.000053 sec (incl time to compute L and U) compute C time: 0.000003 sec -reduce (C) time: 0.000002 sec -rate 0.20 million edges/sec (incl time for U=triu(A)) -rate 2.06 million edges/sec (just tricount itself) -L*U' time (dot): 0.000005 sec +reduce (C) time: 0.000003 sec +rate 0.17 million edges/sec (incl time for U=triu(A)) +rate 1.50 million edges/sec (just tricount itself) +L*U' time (dot): 0.000006 sec (nthreads: 8 speedup 6.84178) +tricount time: 0.000009 sec (dot product method) +tri+prep time: 0.000056 sec (incl time to compute L and U) +compute C time: 0.000006 sec +reduce (C) time: 0.000003 sec +rate 0.16 million edges/sec (incl time for U=triu(A)) +rate 0.98 million edges/sec (just tricount itself) +L*U' time (dot): 0.000008 sec +tricount time: 0.000010 sec (dot product method) +tri+prep time: 0.000057 sec (incl time to compute L and U) +compute C time: 0.000008 sec +reduce (C) time: 0.000003 sec +rate 0.16 million edges/sec (incl time for U=triu(A)) +rate 0.87 million edges/sec (just tricount itself) +L*U' time (dot): 0.000005 sec (nthreads: 2 speedup 1.63061) tricount time: 0.000007 sec (dot product method) -tri+prep time: 0.000048 sec (incl time to compute L and U) +tri+prep time: 0.000054 sec (incl time to compute L and U) compute C time: 0.000005 sec reduce (C) time: 0.000002 sec -rate 0.19 million edges/sec (incl time for U=triu(A)) -rate 1.29 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 2 speedup 1.25108) -tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000047 sec (incl time to compute L and U) -compute C time: 0.000004 sec -reduce (C) time: 0.000002 sec -rate 0.19 million edges/sec (incl time for U=triu(A)) -rate 1.49 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 4 speedup 1.09584) -tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000047 sec (incl time to compute L and U) -compute C time: 0.000004 sec +rate 0.17 million edges/sec (incl time for U=triu(A)) +rate 1.25 million edges/sec (just tricount itself) +L*U' time (dot): 0.000006 sec (nthreads: 4 speedup 1.29289) +tricount time: 0.000009 sec (dot product method) +tri+prep time: 0.000055 sec (incl time to compute L and U) +compute C time: 0.000006 sec reduce (C) time: 0.000002 sec -rate 0.19 million edges/sec (incl time for U=triu(A)) -rate 1.42 million edges/sec (just tricount itself) -L*U' time (dot): 0.000002 sec (nthreads: 8 speedup 2.01637) -tricount time: 0.000004 sec (dot product method) -tri+prep time: 0.000045 sec (incl time to compute L and U) -compute C time: 0.000002 sec +rate 0.16 million edges/sec (incl time for U=triu(A)) +rate 1.06 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 2.37394) +tricount time: 0.000005 sec (dot product method) +tri+prep time: 0.000052 sec (incl time to compute L and U) +compute C time: 0.000003 sec reduce (C) time: 0.000002 sec -rate 0.20 million edges/sec (incl time for U=triu(A)) -rate 2.24 million edges/sec (just tricount itself) +rate 0.17 million edges/sec (incl time for U=triu(A)) +rate 1.73 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000018 sec -tricount time: 0.000019 sec (saxpy method) -tri+prep time: 0.000024 sec (incl time to compute L) -compute C time: 0.000018 sec -reduce (C) time: 0.000000 sec -rate 0.37 million edges/sec (incl time for L=tril(A)) -rate 0.48 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000005 sec (nthreads: 2 speedup 3.96474) -tricount time: 0.000005 sec (saxpy method) -tri+prep time: 0.000010 sec (incl time to compute L) -compute C time: 0.000005 sec -reduce (C) time: 0.000000 sec -rate 0.87 million edges/sec (incl time for L=tril(A)) -rate 1.84 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000004 sec (nthreads: 4 speedup 5.08173) -tricount time: 0.000004 sec (saxpy method) -tri+prep time: 0.000009 sec (incl time to compute L) -compute C time: 0.000004 sec +triangles, method 3: 7 +C=L*L time (saxpy): 0.000029 sec +tricount time: 0.000030 sec (saxpy method) +tri+prep time: 0.000036 sec (incl time to compute L) +compute C time: 0.000029 sec +reduce (C) time: 0.000001 sec +rate 0.25 million edges/sec (incl time for L=tril(A)) +rate 0.30 million edges/sec (just tricount itself) +triangles, method 3: 7 +C=L*L time (saxpy): 0.000007 sec (nthreads: 2 speedup 4.44424) +tricount time: 0.000007 sec (saxpy method) +tri+prep time: 0.000013 sec (incl time to compute L) +compute C time: 0.000007 sec reduce (C) time: 0.000000 sec -rate 0.96 million edges/sec (incl time for L=tril(A)) -rate 2.33 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000005 sec (nthreads: 8 speedup 3.7378) -tricount time: 0.000005 sec (saxpy method) -tri+prep time: 0.000011 sec (incl time to compute L) +rate 0.69 million edges/sec (incl time for L=tril(A)) +rate 1.29 million edges/sec (just tricount itself) +triangles, method 3: 7 +C=L*L time (saxpy): 0.000005 sec (nthreads: 4 speedup 5.59661) +tricount time: 0.000006 sec (saxpy method) +tri+prep time: 0.000012 sec (incl time to compute L) compute C time: 0.000005 sec reduce (C) time: 0.000000 sec -rate 0.84 million edges/sec (incl time for L=tril(A)) -rate 1.70 million edges/sec (just tricount itself) +rate 0.78 million edges/sec (incl time for L=tril(A)) +rate 1.61 million edges/sec (just tricount itself) +triangles, method 3: 7 +C=L*L time (saxpy): 0.000010 sec (nthreads: 8 speedup 3.02562) +tricount time: 0.000011 sec (saxpy method) +tri+prep time: 0.000017 sec (incl time to compute L) +compute C time: 0.000010 sec +reduce (C) time: 0.000001 sec +rate 0.54 million edges/sec (incl time for L=tril(A)) +rate 0.85 million edges/sec (just tricount itself) -------------------------------------------------------------- matrix 3 by 3, 0 entries, from stdin -total time to read A matrix: 0.000138 sec +total time to read A matrix: 0.000168 sec n 3 # edges 0 -U=triu(A) time: 0.000033 sec -L=tril(A) time: 0.000005 sec +U=triu(A) time: 0.000052 sec +L=tril(A) time: 0.000007 sec ------------------------------------- dot product method: # triangles 0 -L*U' time (dot): 0.000025 sec -tricount time: 0.000027 sec (dot product method) -tri+prep time: 0.000065 sec (incl time to compute L and U) -compute C time: 0.000025 sec -reduce (C) time: 0.000003 sec +L*U' time (dot): 0.000039 sec +tricount time: 0.000043 sec (dot product method) +tri+prep time: 0.000102 sec (incl time to compute L and U) +compute C time: 0.000039 sec +reduce (C) time: 0.000004 sec rate 0.00 million edges/sec (incl time for U=triu(A)) rate 0.00 million edges/sec (just tricount itself) -L*U' time (dot): 0.000003 sec (nthreads: 2 speedup 8.4299) -tricount time: 0.000003 sec (dot product method) -tri+prep time: 0.000041 sec (incl time to compute L and U) -compute C time: 0.000003 sec +L*U' time (dot): 0.000004 sec (nthreads: 2 speedup 9.51825) +tricount time: 0.000005 sec (dot product method) +tri+prep time: 0.000064 sec (incl time to compute L and U) +compute C time: 0.000004 sec reduce (C) time: 0.000000 sec rate 0.00 million edges/sec (incl time for U=triu(A)) rate 0.00 million edges/sec (just tricount itself) -L*U' time (dot): 0.000002 sec (nthreads: 4 speedup 11.9314) -tricount time: 0.000002 sec (dot product method) -tri+prep time: 0.000040 sec (incl time to compute L and U) -compute C time: 0.000002 sec +L*U' time (dot): 0.000003 sec (nthreads: 4 speedup 13.9081) +tricount time: 0.000003 sec (dot product method) +tri+prep time: 0.000062 sec (incl time to compute L and U) +compute C time: 0.000003 sec reduce (C) time: 0.000000 sec rate 0.00 million edges/sec (incl time for U=triu(A)) rate 0.00 million edges/sec (just tricount itself) -L*U' time (dot): 0.000002 sec (nthreads: 8 speedup 13.4563) -tricount time: 0.000002 sec (dot product method) -tri+prep time: 0.000040 sec (incl time to compute L and U) +L*U' time (dot): 0.000002 sec (nthreads: 8 speedup 15.989) +tricount time: 0.000003 sec (dot product method) +tri+prep time: 0.000062 sec (incl time to compute L and U) compute C time: 0.000002 sec reduce (C) time: 0.000000 sec rate 0.00 million edges/sec (incl time for U=triu(A)) rate 0.00 million edges/sec (just tricount itself) -L*U' time (dot): 0.000002 sec +L*U' time (dot): 0.000003 sec tricount time: 0.000003 sec (dot product method) -tri+prep time: 0.000040 sec (incl time to compute L and U) -compute C time: 0.000002 sec +tri+prep time: 0.000062 sec (incl time to compute L and U) +compute C time: 0.000003 sec reduce (C) time: 0.000000 sec rate 0.00 million edges/sec (incl time for U=triu(A)) rate 0.00 million edges/sec (just tricount itself) -L*U' time (dot): 0.000002 sec (nthreads: 2 speedup 1.1864) -tricount time: 0.000002 sec (dot product method) -tri+prep time: 0.000040 sec (incl time to compute L and U) -compute C time: 0.000002 sec +L*U' time (dot): 0.000003 sec (nthreads: 2 speedup 0.949015) +tricount time: 0.000003 sec (dot product method) +tri+prep time: 0.000062 sec (incl time to compute L and U) +compute C time: 0.000003 sec reduce (C) time: 0.000000 sec rate 0.00 million edges/sec (incl time for U=triu(A)) rate 0.00 million edges/sec (just tricount itself) -L*U' time (dot): 0.000002 sec (nthreads: 4 speedup 1.17933) -tricount time: 0.000002 sec (dot product method) -tri+prep time: 0.000040 sec (incl time to compute L and U) -compute C time: 0.000002 sec +L*U' time (dot): 0.000003 sec (nthreads: 4 speedup 0.985999) +tricount time: 0.000003 sec (dot product method) +tri+prep time: 0.000062 sec (incl time to compute L and U) +compute C time: 0.000003 sec reduce (C) time: 0.000000 sec rate 0.00 million edges/sec (incl time for U=triu(A)) rate 0.00 million edges/sec (just tricount itself) -L*U' time (dot): 0.000002 sec (nthreads: 8 speedup 1.18819) -tricount time: 0.000002 sec (dot product method) -tri+prep time: 0.000040 sec (incl time to compute L and U) +L*U' time (dot): 0.000002 sec (nthreads: 8 speedup 1.04575) +tricount time: 0.000003 sec (dot product method) +tri+prep time: 0.000062 sec (incl time to compute L and U) compute C time: 0.000002 sec reduce (C) time: 0.000000 sec rate 0.00 million edges/sec (incl time for U=triu(A)) rate 0.00 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000016 sec -tricount time: 0.000016 sec (saxpy method) -tri+prep time: 0.000021 sec (incl time to compute L) -compute C time: 0.000016 sec +triangles, method 3: 0 +C=L*L time (saxpy): 0.000022 sec +tricount time: 0.000023 sec (saxpy method) +tri+prep time: 0.000029 sec (incl time to compute L) +compute C time: 0.000022 sec reduce (C) time: 0.000000 sec rate 0.00 million edges/sec (incl time for L=tril(A)) rate 0.00 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000004 sec (nthreads: 2 speedup 4.13975) -tricount time: 0.000004 sec (saxpy method) -tri+prep time: 0.000009 sec (incl time to compute L) -compute C time: 0.000004 sec +triangles, method 3: 0 +C=L*L time (saxpy): 0.000005 sec (nthreads: 2 speedup 4.57078) +tricount time: 0.000005 sec (saxpy method) +tri+prep time: 0.000012 sec (incl time to compute L) +compute C time: 0.000005 sec reduce (C) time: 0.000000 sec rate 0.00 million edges/sec (incl time for L=tril(A)) rate 0.00 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000003 sec (nthreads: 4 speedup 4.78922) -tricount time: 0.000004 sec (saxpy method) -tri+prep time: 0.000009 sec (incl time to compute L) -compute C time: 0.000003 sec +triangles, method 3: 0 +C=L*L time (saxpy): 0.000004 sec (nthreads: 4 speedup 5.3183) +tricount time: 0.000005 sec (saxpy method) +tri+prep time: 0.000011 sec (incl time to compute L) +compute C time: 0.000004 sec reduce (C) time: 0.000000 sec rate 0.00 million edges/sec (incl time for L=tril(A)) rate 0.00 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000005 sec (nthreads: 8 speedup 3.47362) -tricount time: 0.000005 sec (saxpy method) -tri+prep time: 0.000010 sec (incl time to compute L) -compute C time: 0.000005 sec +triangles, method 3: 0 +C=L*L time (saxpy): 0.000006 sec (nthreads: 8 speedup 3.45239) +tricount time: 0.000007 sec (saxpy method) +tri+prep time: 0.000014 sec (incl time to compute L) +compute C time: 0.000006 sec reduce (C) time: 0.000000 sec rate 0.00 million edges/sec (incl time for L=tril(A)) rate 0.00 million edges/sec (just tricount itself) @@ -295,1666 +307,1734 @@ rate 0.00 million edges/sec (just tricount itself) -------------------------------------------------------------- matrix 4 by 4, 4 entries, from stdin -total time to read A matrix: 0.000148 sec +total time to read A matrix: 0.000174 sec n 4 # edges 2 -U=triu(A) time: 0.000038 sec -L=tril(A) time: 0.000005 sec +U=triu(A) time: 0.000044 sec +L=tril(A) time: 0.000007 sec ------------------------------------- dot product method: # triangles 0 -L*U' time (dot): 0.000028 sec -tricount time: 0.000037 sec (dot product method) -tri+prep time: 0.000079 sec (incl time to compute L and U) -compute C time: 0.000028 sec +L*U' time (dot): 0.000029 sec +tricount time: 0.000039 sec (dot product method) +tri+prep time: 0.000090 sec (incl time to compute L and U) +compute C time: 0.000029 sec reduce (C) time: 0.000009 sec -rate 0.03 million edges/sec (incl time for U=triu(A)) +rate 0.02 million edges/sec (incl time for U=triu(A)) rate 0.05 million edges/sec (just tricount itself) -L*U' time (dot): 0.000005 sec (nthreads: 2 speedup 5.56541) -tricount time: 0.000010 sec (dot product method) -tri+prep time: 0.000052 sec (incl time to compute L and U) -compute C time: 0.000005 sec +L*U' time (dot): 0.000007 sec (nthreads: 2 speedup 4.16357) +tricount time: 0.000012 sec (dot product method) +tri+prep time: 0.000064 sec (incl time to compute L and U) +compute C time: 0.000007 sec reduce (C) time: 0.000005 sec -rate 0.04 million edges/sec (incl time for U=triu(A)) -rate 0.21 million edges/sec (just tricount itself) -L*U' time (dot): 0.000005 sec (nthreads: 4 speedup 5.54574) -tricount time: 0.000008 sec (dot product method) -tri+prep time: 0.000051 sec (incl time to compute L and U) +rate 0.03 million edges/sec (incl time for U=triu(A)) +rate 0.16 million edges/sec (just tricount itself) +L*U' time (dot): 0.000005 sec (nthreads: 4 speedup 5.49784) +tricount time: 0.000009 sec (dot product method) +tri+prep time: 0.000060 sec (incl time to compute L and U) compute C time: 0.000005 sec reduce (C) time: 0.000003 sec -rate 0.04 million edges/sec (incl time for U=triu(A)) -rate 0.24 million edges/sec (just tricount itself) -L*U' time (dot): 0.000002 sec (nthreads: 8 speedup 12.1662) +rate 0.03 million edges/sec (incl time for U=triu(A)) +rate 0.23 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 9.85422) tricount time: 0.000005 sec (dot product method) -tri+prep time: 0.000047 sec (incl time to compute L and U) -compute C time: 0.000002 sec +tri+prep time: 0.000057 sec (incl time to compute L and U) +compute C time: 0.000003 sec reduce (C) time: 0.000002 sec rate 0.04 million edges/sec (incl time for U=triu(A)) -rate 0.43 million edges/sec (just tricount itself) +rate 0.36 million edges/sec (just tricount itself) L*U' time (dot): 0.000003 sec -tricount time: 0.000005 sec (dot product method) -tri+prep time: 0.000047 sec (incl time to compute L and U) +tricount time: 0.000006 sec (dot product method) +tri+prep time: 0.000058 sec (incl time to compute L and U) compute C time: 0.000003 sec reduce (C) time: 0.000003 sec -rate 0.04 million edges/sec (incl time for U=triu(A)) -rate 0.40 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 2 speedup 0.644123) +rate 0.03 million edges/sec (incl time for U=triu(A)) +rate 0.32 million edges/sec (just tricount itself) +L*U' time (dot): 0.000005 sec (nthreads: 2 speedup 0.592958) tricount time: 0.000008 sec (dot product method) -tri+prep time: 0.000051 sec (incl time to compute L and U) -compute C time: 0.000004 sec -reduce (C) time: 0.000004 sec -rate 0.04 million edges/sec (incl time for U=triu(A)) -rate 0.25 million edges/sec (just tricount itself) -L*U' time (dot): 0.000005 sec (nthreads: 4 speedup 0.545989) -tricount time: 0.000007 sec (dot product method) -tri+prep time: 0.000050 sec (incl time to compute L and U) +tri+prep time: 0.000060 sec (incl time to compute L and U) compute C time: 0.000005 sec reduce (C) time: 0.000003 sec -rate 0.04 million edges/sec (incl time for U=triu(A)) -rate 0.27 million edges/sec (just tricount itself) -L*U' time (dot): 0.000002 sec (nthreads: 8 speedup 1.134) -tricount time: 0.000004 sec (dot product method) -tri+prep time: 0.000047 sec (incl time to compute L and U) -compute C time: 0.000002 sec +rate 0.03 million edges/sec (incl time for U=triu(A)) +rate 0.24 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 4 speedup 1.04212) +tricount time: 0.000005 sec (dot product method) +tri+prep time: 0.000057 sec (incl time to compute L and U) +compute C time: 0.000003 sec reduce (C) time: 0.000002 sec rate 0.04 million edges/sec (incl time for U=triu(A)) -rate 0.45 million edges/sec (just tricount itself) +rate 0.38 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 1.20878) +tricount time: 0.000006 sec (dot product method) +tri+prep time: 0.000057 sec (incl time to compute L and U) +compute C time: 0.000003 sec +reduce (C) time: 0.000003 sec +rate 0.03 million edges/sec (incl time for U=triu(A)) +rate 0.36 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000040 sec -tricount time: 0.000041 sec (saxpy method) -tri+prep time: 0.000046 sec (incl time to compute L) -compute C time: 0.000040 sec +triangles, method 3: 0 +C=L*L time (saxpy): 0.000042 sec +tricount time: 0.000043 sec (saxpy method) +tri+prep time: 0.000050 sec (incl time to compute L) +compute C time: 0.000042 sec reduce (C) time: 0.000001 sec rate 0.04 million edges/sec (incl time for L=tril(A)) rate 0.05 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000018 sec (nthreads: 2 speedup 2.21528) -tricount time: 0.000019 sec (saxpy method) -tri+prep time: 0.000024 sec (incl time to compute L) -compute C time: 0.000018 sec +triangles, method 3: 0 +C=L*L time (saxpy): 0.000014 sec (nthreads: 2 speedup 2.90987) +tricount time: 0.000015 sec (saxpy method) +tri+prep time: 0.000022 sec (incl time to compute L) +compute C time: 0.000014 sec +reduce (C) time: 0.000000 sec +rate 0.09 million edges/sec (incl time for L=tril(A)) +rate 0.13 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000014 sec (nthreads: 4 speedup 3.02766) +tricount time: 0.000014 sec (saxpy method) +tri+prep time: 0.000022 sec (incl time to compute L) +compute C time: 0.000014 sec reduce (C) time: 0.000001 sec +rate 0.09 million edges/sec (incl time for L=tril(A)) +rate 0.14 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000017 sec (nthreads: 8 speedup 2.42674) +tricount time: 0.000018 sec (saxpy method) +tri+prep time: 0.000025 sec (incl time to compute L) +compute C time: 0.000017 sec +reduce (C) time: 0.000000 sec rate 0.08 million edges/sec (incl time for L=tril(A)) rate 0.11 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000019 sec (nthreads: 4 speedup 2.15104) -tricount time: 0.000019 sec (saxpy method) -tri+prep time: 0.000024 sec (incl time to compute L) -compute C time: 0.000019 sec -reduce (C) time: 0.000001 sec -rate 0.08 million edges/sec (incl time for L=tril(A)) -rate 0.10 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000024 sec (nthreads: 8 speedup 1.64287) -tricount time: 0.000025 sec (saxpy method) -tri+prep time: 0.000030 sec (incl time to compute L) -compute C time: 0.000024 sec -reduce (C) time: 0.000001 sec -rate 0.07 million edges/sec (incl time for L=tril(A)) -rate 0.08 million edges/sec (just tricount itself) -------------------------------------------------------------- matrix 4 by 4, 10 entries, from stdin -total time to read A matrix: 0.000188 sec +total time to read A matrix: 0.000112 sec n 4 # edges 5 -U=triu(A) time: 0.000038 sec +U=triu(A) time: 0.000024 sec L=tril(A) time: 0.000005 sec ------------------------------------- dot product method: # triangles 2 -L*U' time (dot): 0.000030 sec -tricount time: 0.000038 sec (dot product method) -tri+prep time: 0.000080 sec (incl time to compute L and U) -compute C time: 0.000030 sec -reduce (C) time: 0.000008 sec -rate 0.06 million edges/sec (incl time for U=triu(A)) -rate 0.13 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 2 speedup 8.52063) -tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000049 sec (incl time to compute L and U) +L*U' time (dot): 0.000021 sec +tricount time: 0.000027 sec (dot product method) +tri+prep time: 0.000056 sec (incl time to compute L and U) +compute C time: 0.000021 sec +reduce (C) time: 0.000006 sec +rate 0.09 million edges/sec (incl time for U=triu(A)) +rate 0.18 million edges/sec (just tricount itself) +L*U' time (dot): 0.000004 sec (nthreads: 2 speedup 4.75515) +tricount time: 0.000007 sec (dot product method) +tri+prep time: 0.000035 sec (incl time to compute L and U) compute C time: 0.000004 sec reduce (C) time: 0.000002 sec -rate 0.10 million edges/sec (incl time for U=triu(A)) -rate 0.87 million edges/sec (just tricount itself) -L*U' time (dot): 0.000003 sec (nthreads: 4 speedup 11.9581) +rate 0.14 million edges/sec (incl time for U=triu(A)) +rate 0.74 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 4 speedup 6.41806) +tricount time: 0.000005 sec (dot product method) +tri+prep time: 0.000034 sec (incl time to compute L and U) +compute C time: 0.000003 sec +reduce (C) time: 0.000002 sec +rate 0.15 million edges/sec (incl time for U=triu(A)) +rate 0.98 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 7.51145) tricount time: 0.000004 sec (dot product method) -tri+prep time: 0.000047 sec (incl time to compute L and U) +tri+prep time: 0.000033 sec (incl time to compute L and U) compute C time: 0.000003 sec reduce (C) time: 0.000002 sec -rate 0.11 million edges/sec (incl time for U=triu(A)) +rate 0.15 million edges/sec (incl time for U=triu(A)) rate 1.12 million edges/sec (just tricount itself) -L*U' time (dot): 0.000002 sec (nthreads: 8 speedup 13.6524) -tricount time: 0.000004 sec (dot product method) -tri+prep time: 0.000047 sec (incl time to compute L and U) -compute C time: 0.000002 sec +L*U' time (dot): 0.000003 sec +tricount time: 0.000005 sec (dot product method) +tri+prep time: 0.000033 sec (incl time to compute L and U) +compute C time: 0.000003 sec reduce (C) time: 0.000002 sec -rate 0.11 million edges/sec (incl time for U=triu(A)) -rate 1.23 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec -tricount time: 0.000008 sec (dot product method) -tri+prep time: 0.000050 sec (incl time to compute L and U) -compute C time: 0.000004 sec -reduce (C) time: 0.000003 sec -rate 0.10 million edges/sec (incl time for U=triu(A)) -rate 0.66 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 2 speedup 1.01534) -tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000049 sec (incl time to compute L and U) -compute C time: 0.000004 sec +rate 0.15 million edges/sec (incl time for U=triu(A)) +rate 1.00 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 2 speedup 1.02638) +tricount time: 0.000005 sec (dot product method) +tri+prep time: 0.000033 sec (incl time to compute L and U) +compute C time: 0.000003 sec reduce (C) time: 0.000002 sec -rate 0.10 million edges/sec (incl time for U=triu(A)) -rate 0.81 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 4 speedup 1.07426) -tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000049 sec (incl time to compute L and U) -compute C time: 0.000004 sec +rate 0.15 million edges/sec (incl time for U=triu(A)) +rate 1.07 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 4 speedup 1.11222) +tricount time: 0.000004 sec (dot product method) +tri+prep time: 0.000033 sec (incl time to compute L and U) +compute C time: 0.000003 sec reduce (C) time: 0.000002 sec -rate 0.10 million edges/sec (incl time for U=triu(A)) -rate 0.86 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 8 speedup 1.02727) -tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000049 sec (incl time to compute L and U) -compute C time: 0.000004 sec +rate 0.15 million edges/sec (incl time for U=triu(A)) +rate 1.14 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 1.11541) +tricount time: 0.000004 sec (dot product method) +tri+prep time: 0.000033 sec (incl time to compute L and U) +compute C time: 0.000003 sec reduce (C) time: 0.000002 sec -rate 0.10 million edges/sec (incl time for U=triu(A)) -rate 0.83 million edges/sec (just tricount itself) +rate 0.15 million edges/sec (incl time for U=triu(A)) +rate 1.16 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000025 sec -tricount time: 0.000026 sec (saxpy method) -tri+prep time: 0.000031 sec (incl time to compute L) -compute C time: 0.000025 sec -reduce (C) time: 0.000001 sec -rate 0.16 million edges/sec (incl time for L=tril(A)) -rate 0.19 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000007 sec (nthreads: 2 speedup 3.8032) -tricount time: 0.000007 sec (saxpy method) -tri+prep time: 0.000012 sec (incl time to compute L) -compute C time: 0.000007 sec +triangles, method 3: 2 +C=L*L time (saxpy): 0.000018 sec +tricount time: 0.000019 sec (saxpy method) +tri+prep time: 0.000024 sec (incl time to compute L) +compute C time: 0.000018 sec reduce (C) time: 0.000000 sec -rate 0.41 million edges/sec (incl time for L=tril(A)) -rate 0.71 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000006 sec (nthreads: 4 speedup 4.31124) +rate 0.21 million edges/sec (incl time for L=tril(A)) +rate 0.27 million edges/sec (just tricount itself) +triangles, method 3: 2 +C=L*L time (saxpy): 0.000006 sec (nthreads: 2 speedup 3.25856) tricount time: 0.000006 sec (saxpy method) tri+prep time: 0.000011 sec (incl time to compute L) compute C time: 0.000006 sec reduce (C) time: 0.000000 sec -rate 0.44 million edges/sec (incl time for L=tril(A)) -rate 0.81 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000005 sec (nthreads: 8 speedup 5.42519) +rate 0.46 million edges/sec (incl time for L=tril(A)) +rate 0.84 million edges/sec (just tricount itself) +triangles, method 3: 2 +C=L*L time (saxpy): 0.000005 sec (nthreads: 4 speedup 3.87265) tricount time: 0.000005 sec (saxpy method) tri+prep time: 0.000010 sec (incl time to compute L) compute C time: 0.000005 sec reduce (C) time: 0.000000 sec -rate 0.49 million edges/sec (incl time for L=tril(A)) -rate 0.98 million edges/sec (just tricount itself) +rate 0.50 million edges/sec (incl time for L=tril(A)) +rate 0.99 million edges/sec (just tricount itself) +triangles, method 3: 2 +C=L*L time (saxpy): 0.000005 sec (nthreads: 8 speedup 3.318) +tricount time: 0.000006 sec (saxpy method) +tri+prep time: 0.000011 sec (incl time to compute L) +compute C time: 0.000005 sec +reduce (C) time: 0.000000 sec +rate 0.46 million edges/sec (incl time for L=tril(A)) +rate 0.84 million edges/sec (just tricount itself) -------------------------------------------------------------- matrix 7 by 7, 16 entries, from stdin -total time to read A matrix: 0.000156 sec +total time to read A matrix: 0.000151 sec n 7 # edges 8 -U=triu(A) time: 0.000019 sec +U=triu(A) time: 0.000020 sec L=tril(A) time: 0.000005 sec ------------------------------------- dot product method: # triangles 0 -L*U' time (dot): 0.000020 sec -tricount time: 0.000026 sec (dot product method) -tri+prep time: 0.000050 sec (incl time to compute L and U) -compute C time: 0.000020 sec +L*U' time (dot): 0.000027 sec +tricount time: 0.000034 sec (dot product method) +tri+prep time: 0.000059 sec (incl time to compute L and U) +compute C time: 0.000027 sec reduce (C) time: 0.000007 sec -rate 0.16 million edges/sec (incl time for U=triu(A)) -rate 0.30 million edges/sec (just tricount itself) -L*U' time (dot): 0.000005 sec (nthreads: 2 speedup 3.78177) +rate 0.14 million edges/sec (incl time for U=triu(A)) +rate 0.24 million edges/sec (just tricount itself) +L*U' time (dot): 0.000005 sec (nthreads: 2 speedup 5.12151) tricount time: 0.000009 sec (dot product method) -tri+prep time: 0.000032 sec (incl time to compute L and U) +tri+prep time: 0.000034 sec (incl time to compute L and U) compute C time: 0.000005 sec reduce (C) time: 0.000003 sec -rate 0.25 million edges/sec (incl time for U=triu(A)) -rate 0.92 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 4 speedup 5.03558) -tricount time: 0.000007 sec (dot product method) -tri+prep time: 0.000031 sec (incl time to compute L and U) -compute C time: 0.000004 sec -reduce (C) time: 0.000003 sec -rate 0.26 million edges/sec (incl time for U=triu(A)) -rate 1.17 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 8 speedup 5.07063) -tricount time: 0.000007 sec (dot product method) -tri+prep time: 0.000031 sec (incl time to compute L and U) -compute C time: 0.000004 sec -reduce (C) time: 0.000003 sec +rate 0.24 million edges/sec (incl time for U=triu(A)) +rate 0.93 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 4 speedup 9.05404) +tricount time: 0.000005 sec (dot product method) +tri+prep time: 0.000030 sec (incl time to compute L and U) +compute C time: 0.000003 sec +reduce (C) time: 0.000002 sec rate 0.26 million edges/sec (incl time for U=triu(A)) -rate 1.19 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec -tricount time: 0.000008 sec (dot product method) -tri+prep time: 0.000032 sec (incl time to compute L and U) -compute C time: 0.000004 sec +rate 1.46 million edges/sec (just tricount itself) +L*U' time (dot): 0.000006 sec (nthreads: 8 speedup 4.59057) +tricount time: 0.000010 sec (dot product method) +tri+prep time: 0.000035 sec (incl time to compute L and U) +compute C time: 0.000006 sec reduce (C) time: 0.000004 sec -rate 0.25 million edges/sec (incl time for U=triu(A)) -rate 1.03 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 2 speedup 0.982245) +rate 0.23 million edges/sec (incl time for U=triu(A)) +rate 0.79 million edges/sec (just tricount itself) +L*U' time (dot): 0.000004 sec tricount time: 0.000007 sec (dot product method) -tri+prep time: 0.000031 sec (incl time to compute L and U) +tri+prep time: 0.000032 sec (incl time to compute L and U) compute C time: 0.000004 sec reduce (C) time: 0.000003 sec -rate 0.26 million edges/sec (incl time for U=triu(A)) -rate 1.09 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 4 speedup 0.984639) -tricount time: 0.000007 sec (dot product method) +rate 0.25 million edges/sec (incl time for U=triu(A)) +rate 1.16 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 2 speedup 1.18959) +tricount time: 0.000006 sec (dot product method) tri+prep time: 0.000031 sec (incl time to compute L and U) -compute C time: 0.000004 sec +compute C time: 0.000003 sec reduce (C) time: 0.000003 sec rate 0.26 million edges/sec (incl time for U=triu(A)) -rate 1.09 million edges/sec (just tricount itself) -L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 1.49371) +rate 1.28 million edges/sec (just tricount itself) +L*U' time (dot): 0.000006 sec (nthreads: 4 speedup 0.659947) +tricount time: 0.000009 sec (dot product method) +tri+prep time: 0.000034 sec (incl time to compute L and U) +compute C time: 0.000006 sec +reduce (C) time: 0.000004 sec +rate 0.23 million edges/sec (incl time for U=triu(A)) +rate 0.86 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 1.16779) tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000029 sec (incl time to compute L and U) +tri+prep time: 0.000031 sec (incl time to compute L and U) compute C time: 0.000003 sec reduce (C) time: 0.000003 sec -rate 0.27 million edges/sec (incl time for U=triu(A)) -rate 1.42 million edges/sec (just tricount itself) +rate 0.26 million edges/sec (incl time for U=triu(A)) +rate 1.31 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000022 sec -tricount time: 0.000022 sec (saxpy method) -tri+prep time: 0.000027 sec (incl time to compute L) -compute C time: 0.000022 sec -reduce (C) time: 0.000000 sec -rate 0.30 million edges/sec (incl time for L=tril(A)) -rate 0.36 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000012 sec (nthreads: 2 speedup 1.85364) -tricount time: 0.000012 sec (saxpy method) -tri+prep time: 0.000017 sec (incl time to compute L) -compute C time: 0.000012 sec -reduce (C) time: 0.000000 sec -rate 0.48 million edges/sec (incl time for L=tril(A)) -rate 0.67 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000012 sec (nthreads: 4 speedup 1.75144) -tricount time: 0.000013 sec (saxpy method) -tri+prep time: 0.000017 sec (incl time to compute L) -compute C time: 0.000012 sec -reduce (C) time: 0.000000 sec -rate 0.46 million edges/sec (incl time for L=tril(A)) -rate 0.63 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000026 sec (nthreads: 8 speedup 0.816327) -tricount time: 0.000027 sec (saxpy method) -tri+prep time: 0.000031 sec (incl time to compute L) -compute C time: 0.000026 sec +triangles, method 3: 0 +C=L*L time (saxpy): 0.000029 sec +tricount time: 0.000029 sec (saxpy method) +tri+prep time: 0.000035 sec (incl time to compute L) +compute C time: 0.000029 sec +reduce (C) time: 0.000001 sec +rate 0.23 million edges/sec (incl time for L=tril(A)) +rate 0.27 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000014 sec (nthreads: 2 speedup 2.0437) +tricount time: 0.000014 sec (saxpy method) +tri+prep time: 0.000020 sec (incl time to compute L) +compute C time: 0.000014 sec reduce (C) time: 0.000000 sec -rate 0.25 million edges/sec (incl time for L=tril(A)) -rate 0.30 million edges/sec (just tricount itself) +rate 0.41 million edges/sec (incl time for L=tril(A)) +rate 0.55 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000013 sec (nthreads: 4 speedup 2.19743) +tricount time: 0.000014 sec (saxpy method) +tri+prep time: 0.000019 sec (incl time to compute L) +compute C time: 0.000013 sec +reduce (C) time: 0.000001 sec +rate 0.43 million edges/sec (incl time for L=tril(A)) +rate 0.59 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000035 sec (nthreads: 8 speedup 0.811284) +tricount time: 0.000036 sec (saxpy method) +tri+prep time: 0.000041 sec (incl time to compute L) +compute C time: 0.000035 sec +reduce (C) time: 0.000001 sec +rate 0.20 million edges/sec (incl time for L=tril(A)) +rate 0.22 million edges/sec (just tricount itself) -------------------------------------------------------------- matrix 304 by 304, 876 entries, from stdin -total time to read A matrix: 0.000336 sec +total time to read A matrix: 0.000324 sec n 304 # edges 438 -U=triu(A) time: 0.000027 sec -L=tril(A) time: 0.000008 sec +U=triu(A) time: 0.000021 sec +L=tril(A) time: 0.000007 sec ------------------------------------- dot product method: # triangles 0 -L*U' time (dot): 0.000026 sec -tricount time: 0.000036 sec (dot product method) -tri+prep time: 0.000071 sec (incl time to compute L and U) -compute C time: 0.000026 sec +L*U' time (dot): 0.000029 sec +tricount time: 0.000039 sec (dot product method) +tri+prep time: 0.000066 sec (incl time to compute L and U) +compute C time: 0.000029 sec reduce (C) time: 0.000010 sec -rate 6.15 million edges/sec (incl time for U=triu(A)) -rate 12.12 million edges/sec (just tricount itself) -L*U' time (dot): 0.000016 sec (nthreads: 2 speedup 1.58173) -tricount time: 0.000025 sec (dot product method) -tri+prep time: 0.000060 sec (incl time to compute L and U) -compute C time: 0.000016 sec -reduce (C) time: 0.000009 sec -rate 7.29 million edges/sec (incl time for U=triu(A)) -rate 17.49 million edges/sec (just tricount itself) -L*U' time (dot): 0.000016 sec (nthreads: 4 speedup 1.61796) -tricount time: 0.000024 sec (dot product method) -tri+prep time: 0.000059 sec (incl time to compute L and U) -compute C time: 0.000016 sec -reduce (C) time: 0.000008 sec -rate 7.40 million edges/sec (incl time for U=triu(A)) -rate 18.15 million edges/sec (just tricount itself) -L*U' time (dot): 0.000015 sec (nthreads: 8 speedup 1.67222) -tricount time: 0.000024 sec (dot product method) -tri+prep time: 0.000059 sec (incl time to compute L and U) -compute C time: 0.000015 sec -reduce (C) time: 0.000009 sec -rate 7.41 million edges/sec (incl time for U=triu(A)) -rate 18.22 million edges/sec (just tricount itself) -L*U' time (dot): 0.000015 sec -tricount time: 0.000024 sec (dot product method) -tri+prep time: 0.000059 sec (incl time to compute L and U) -compute C time: 0.000015 sec -reduce (C) time: 0.000009 sec -rate 7.44 million edges/sec (incl time for U=triu(A)) -rate 18.39 million edges/sec (just tricount itself) -L*U' time (dot): 0.000014 sec (nthreads: 2 speedup 1.07105) -tricount time: 0.000022 sec (dot product method) -tri+prep time: 0.000058 sec (incl time to compute L and U) -compute C time: 0.000014 sec -reduce (C) time: 0.000009 sec -rate 7.61 million edges/sec (incl time for U=triu(A)) -rate 19.51 million edges/sec (just tricount itself) -L*U' time (dot): 0.000015 sec (nthreads: 4 speedup 1.00587) -tricount time: 0.000024 sec (dot product method) -tri+prep time: 0.000059 sec (incl time to compute L and U) -compute C time: 0.000015 sec -reduce (C) time: 0.000009 sec -rate 7.44 million edges/sec (incl time for U=triu(A)) -rate 18.38 million edges/sec (just tricount itself) -L*U' time (dot): 0.000015 sec (nthreads: 8 speedup 1.00443) -tricount time: 0.000023 sec (dot product method) -tri+prep time: 0.000058 sec (incl time to compute L and U) -compute C time: 0.000015 sec -reduce (C) time: 0.000008 sec -rate 7.54 million edges/sec (incl time for U=triu(A)) -rate 19.06 million edges/sec (just tricount itself) +rate 6.59 million edges/sec (incl time for U=triu(A)) +rate 11.34 million edges/sec (just tricount itself) +L*U' time (dot): 0.000011 sec (nthreads: 2 speedup 2.6523) +tricount time: 0.000017 sec (dot product method) +tri+prep time: 0.000045 sec (incl time to compute L and U) +compute C time: 0.000011 sec +reduce (C) time: 0.000007 sec +rate 9.66 million edges/sec (incl time for U=triu(A)) +rate 25.07 million edges/sec (just tricount itself) +L*U' time (dot): 0.000010 sec (nthreads: 4 speedup 3.01903) +tricount time: 0.000015 sec (dot product method) +tri+prep time: 0.000043 sec (incl time to compute L and U) +compute C time: 0.000010 sec +reduce (C) time: 0.000006 sec +rate 10.12 million edges/sec (incl time for U=triu(A)) +rate 28.41 million edges/sec (just tricount itself) +L*U' time (dot): 0.000009 sec (nthreads: 8 speedup 3.12291) +tricount time: 0.000015 sec (dot product method) +tri+prep time: 0.000043 sec (incl time to compute L and U) +compute C time: 0.000009 sec +reduce (C) time: 0.000005 sec +rate 10.29 million edges/sec (incl time for U=triu(A)) +rate 29.82 million edges/sec (just tricount itself) +L*U' time (dot): 0.000009 sec +tricount time: 0.000014 sec (dot product method) +tri+prep time: 0.000042 sec (incl time to compute L and U) +compute C time: 0.000009 sec +reduce (C) time: 0.000005 sec +rate 10.50 million edges/sec (incl time for U=triu(A)) +rate 31.63 million edges/sec (just tricount itself) +L*U' time (dot): 0.000008 sec (nthreads: 2 speedup 1.04126) +tricount time: 0.000013 sec (dot product method) +tri+prep time: 0.000041 sec (incl time to compute L and U) +compute C time: 0.000008 sec +reduce (C) time: 0.000005 sec +rate 10.69 million edges/sec (incl time for U=triu(A)) +rate 33.47 million edges/sec (just tricount itself) +L*U' time (dot): 0.000008 sec (nthreads: 4 speedup 1.02962) +tricount time: 0.000013 sec (dot product method) +tri+prep time: 0.000041 sec (incl time to compute L and U) +compute C time: 0.000008 sec +reduce (C) time: 0.000005 sec +rate 10.66 million edges/sec (incl time for U=triu(A)) +rate 33.15 million edges/sec (just tricount itself) +L*U' time (dot): 0.000008 sec (nthreads: 8 speedup 1.06811) +tricount time: 0.000013 sec (dot product method) +tri+prep time: 0.000041 sec (incl time to compute L and U) +compute C time: 0.000008 sec +reduce (C) time: 0.000005 sec +rate 10.79 million edges/sec (incl time for U=triu(A)) +rate 34.38 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000043 sec -tricount time: 0.000044 sec (saxpy method) -tri+prep time: 0.000052 sec (incl time to compute L) -compute C time: 0.000043 sec -reduce (C) time: 0.000001 sec -rate 8.50 million edges/sec (incl time for L=tril(A)) -rate 9.99 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000030 sec (nthreads: 2 speedup 1.45681) -tricount time: 0.000030 sec (saxpy method) -tri+prep time: 0.000038 sec (incl time to compute L) -compute C time: 0.000030 sec -reduce (C) time: 0.000001 sec -rate 11.58 million edges/sec (incl time for L=tril(A)) -rate 14.53 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000029 sec (nthreads: 4 speedup 1.46942) -tricount time: 0.000030 sec (saxpy method) -tri+prep time: 0.000038 sec (incl time to compute L) -compute C time: 0.000029 sec +triangles, method 3: 0 +C=L*L time (saxpy): 0.000028 sec +tricount time: 0.000028 sec (saxpy method) +tri+prep time: 0.000036 sec (incl time to compute L) +compute C time: 0.000028 sec reduce (C) time: 0.000000 sec -rate 11.67 million edges/sec (incl time for L=tril(A)) -rate 14.67 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000035 sec (nthreads: 8 speedup 1.23519) -tricount time: 0.000035 sec (saxpy method) -tri+prep time: 0.000043 sec (incl time to compute L) -compute C time: 0.000035 sec -reduce (C) time: 0.000001 sec -rate 10.15 million edges/sec (incl time for L=tril(A)) -rate 12.35 million edges/sec (just tricount itself) +rate 12.34 million edges/sec (incl time for L=tril(A)) +rate 15.52 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000020 sec (nthreads: 2 speedup 1.37094) +tricount time: 0.000021 sec (saxpy method) +tri+prep time: 0.000028 sec (incl time to compute L) +compute C time: 0.000020 sec +reduce (C) time: 0.000000 sec +rate 15.64 million edges/sec (incl time for L=tril(A)) +rate 21.15 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000019 sec (nthreads: 4 speedup 1.46644) +tricount time: 0.000019 sec (saxpy method) +tri+prep time: 0.000027 sec (incl time to compute L) +compute C time: 0.000019 sec +reduce (C) time: 0.000000 sec +rate 16.49 million edges/sec (incl time for L=tril(A)) +rate 22.72 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000025 sec (nthreads: 8 speedup 1.09045) +tricount time: 0.000026 sec (saxpy method) +tri+prep time: 0.000033 sec (incl time to compute L) +compute C time: 0.000025 sec +reduce (C) time: 0.000000 sec +rate 13.17 million edges/sec (incl time for L=tril(A)) +rate 16.87 million edges/sec (just tricount itself) -------------------------------------------------------------- matrix 48 by 48, 352 entries, from stdin -total time to read A matrix: 0.000328 sec +total time to read A matrix: 0.000230 sec n 48 # edges 176 -U=triu(A) time: 0.000035 sec -L=tril(A) time: 0.000009 sec +U=triu(A) time: 0.000027 sec +L=tril(A) time: 0.000006 sec ------------------------------------- dot product method: # triangles 160 -L*U' time (dot): 0.000039 sec -tricount time: 0.000050 sec (dot product method) -tri+prep time: 0.000094 sec (incl time to compute L and U) -compute C time: 0.000039 sec -reduce (C) time: 0.000011 sec -rate 1.87 million edges/sec (incl time for U=triu(A)) -rate 3.54 million edges/sec (just tricount itself) -L*U' time (dot): 0.000011 sec (nthreads: 2 speedup 3.60124) -tricount time: 0.000015 sec (dot product method) -tri+prep time: 0.000059 sec (incl time to compute L and U) -compute C time: 0.000011 sec +L*U' time (dot): 0.000027 sec +tricount time: 0.000034 sec (dot product method) +tri+prep time: 0.000068 sec (incl time to compute L and U) +compute C time: 0.000027 sec +reduce (C) time: 0.000007 sec +rate 2.60 million edges/sec (incl time for U=triu(A)) +rate 5.16 million edges/sec (just tricount itself) +L*U' time (dot): 0.000010 sec (nthreads: 2 speedup 2.57265) +tricount time: 0.000014 sec (dot product method) +tri+prep time: 0.000048 sec (incl time to compute L and U) +compute C time: 0.000010 sec reduce (C) time: 0.000004 sec -rate 2.99 million edges/sec (incl time for U=triu(A)) -rate 12.01 million edges/sec (just tricount itself) -L*U' time (dot): 0.000008 sec (nthreads: 4 speedup 4.82118) -tricount time: 0.000011 sec (dot product method) -tri+prep time: 0.000055 sec (incl time to compute L and U) -compute C time: 0.000008 sec -reduce (C) time: 0.000003 sec -rate 3.20 million edges/sec (incl time for U=triu(A)) -rate 16.24 million edges/sec (just tricount itself) -L*U' time (dot): 0.000008 sec (nthreads: 8 speedup 5.09536) -tricount time: 0.000010 sec (dot product method) -tri+prep time: 0.000055 sec (incl time to compute L and U) +rate 3.70 million edges/sec (incl time for U=triu(A)) +rate 12.62 million edges/sec (just tricount itself) +L*U' time (dot): 0.000008 sec (nthreads: 4 speedup 3.32946) +tricount time: 0.000012 sec (dot product method) +tri+prep time: 0.000045 sec (incl time to compute L and U) compute C time: 0.000008 sec -reduce (C) time: 0.000003 sec -rate 3.22 million edges/sec (incl time for U=triu(A)) -rate 16.86 million edges/sec (just tricount itself) -L*U' time (dot): 0.000012 sec -tricount time: 0.000016 sec (dot product method) -tri+prep time: 0.000060 sec (incl time to compute L and U) -compute C time: 0.000012 sec reduce (C) time: 0.000004 sec -rate 2.93 million edges/sec (incl time for U=triu(A)) -rate 11.11 million edges/sec (just tricount itself) -L*U' time (dot): 0.000010 sec (nthreads: 2 speedup 1.2077) +rate 3.90 million edges/sec (incl time for U=triu(A)) +rate 15.24 million edges/sec (just tricount itself) +L*U' time (dot): 0.000010 sec (nthreads: 8 speedup 2.6774) tricount time: 0.000013 sec (dot product method) -tri+prep time: 0.000057 sec (incl time to compute L and U) +tri+prep time: 0.000047 sec (incl time to compute L and U) compute C time: 0.000010 sec reduce (C) time: 0.000003 sec -rate 3.07 million edges/sec (incl time for U=triu(A)) -rate 13.37 million edges/sec (just tricount itself) -L*U' time (dot): 0.000009 sec (nthreads: 4 speedup 1.38824) -tricount time: 0.000012 sec (dot product method) -tri+prep time: 0.000056 sec (incl time to compute L and U) -compute C time: 0.000009 sec +rate 3.78 million edges/sec (incl time for U=triu(A)) +rate 13.55 million edges/sec (just tricount itself) +L*U' time (dot): 0.000011 sec +tricount time: 0.000015 sec (dot product method) +tri+prep time: 0.000048 sec (incl time to compute L and U) +compute C time: 0.000011 sec +reduce (C) time: 0.000004 sec +rate 3.64 million edges/sec (incl time for U=triu(A)) +rate 11.91 million edges/sec (just tricount itself) +L*U' time (dot): 0.000010 sec (nthreads: 2 speedup 1.10836) +tricount time: 0.000014 sec (dot product method) +tri+prep time: 0.000048 sec (incl time to compute L and U) +compute C time: 0.000010 sec +reduce (C) time: 0.000004 sec +rate 3.67 million edges/sec (incl time for U=triu(A)) +rate 12.25 million edges/sec (just tricount itself) +L*U' time (dot): 0.000010 sec (nthreads: 4 speedup 1.10109) +tricount time: 0.000013 sec (dot product method) +tri+prep time: 0.000047 sec (incl time to compute L and U) +compute C time: 0.000010 sec reduce (C) time: 0.000003 sec -rate 3.15 million edges/sec (incl time for U=triu(A)) -rate 15.17 million edges/sec (just tricount itself) -L*U' time (dot): 0.000008 sec (nthreads: 8 speedup 1.55024) +rate 3.77 million edges/sec (incl time for U=triu(A)) +rate 13.40 million edges/sec (just tricount itself) +L*U' time (dot): 0.000007 sec (nthreads: 8 speedup 1.50666) tricount time: 0.000010 sec (dot product method) -tri+prep time: 0.000055 sec (incl time to compute L and U) -compute C time: 0.000008 sec -reduce (C) time: 0.000003 sec -rate 3.22 million edges/sec (incl time for U=triu(A)) -rate 16.95 million edges/sec (just tricount itself) +tri+prep time: 0.000043 sec (incl time to compute L and U) +compute C time: 0.000007 sec +reduce (C) time: 0.000002 sec +rate 4.06 million edges/sec (incl time for U=triu(A)) +rate 17.96 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000032 sec -tricount time: 0.000033 sec (saxpy method) -tri+prep time: 0.000042 sec (incl time to compute L) -compute C time: 0.000032 sec +triangles, method 3: 160 +C=L*L time (saxpy): 0.000031 sec +tricount time: 0.000032 sec (saxpy method) +tri+prep time: 0.000038 sec (incl time to compute L) +compute C time: 0.000031 sec reduce (C) time: 0.000001 sec -rate 4.20 million edges/sec (incl time for L=tril(A)) -rate 5.31 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000014 sec (nthreads: 2 speedup 2.30991) -tricount time: 0.000015 sec (saxpy method) -tri+prep time: 0.000023 sec (incl time to compute L) -compute C time: 0.000014 sec +rate 4.59 million edges/sec (incl time for L=tril(A)) +rate 5.51 million edges/sec (just tricount itself) +triangles, method 3: 160 +C=L*L time (saxpy): 0.000015 sec (nthreads: 2 speedup 2.0114) +tricount time: 0.000016 sec (saxpy method) +tri+prep time: 0.000022 sec (incl time to compute L) +compute C time: 0.000015 sec reduce (C) time: 0.000001 sec -rate 7.51 million edges/sec (incl time for L=tril(A)) -rate 12.02 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000011 sec (nthreads: 4 speedup 2.91911) -tricount time: 0.000012 sec (saxpy method) +rate 7.84 million edges/sec (incl time for L=tril(A)) +rate 10.98 million edges/sec (just tricount itself) +triangles, method 3: 160 +C=L*L time (saxpy): 0.000012 sec (nthreads: 4 speedup 2.52172) +tricount time: 0.000013 sec (saxpy method) tri+prep time: 0.000020 sec (incl time to compute L) -compute C time: 0.000011 sec +compute C time: 0.000012 sec reduce (C) time: 0.000001 sec -rate 8.60 million edges/sec (incl time for L=tril(A)) -rate 15.07 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000011 sec (nthreads: 8 speedup 2.88764) -tricount time: 0.000012 sec (saxpy method) -tri+prep time: 0.000021 sec (incl time to compute L) -compute C time: 0.000011 sec +rate 8.98 million edges/sec (incl time for L=tril(A)) +rate 13.34 million edges/sec (just tricount itself) +triangles, method 3: 160 +C=L*L time (saxpy): 0.000015 sec (nthreads: 8 speedup 2.03312) +tricount time: 0.000016 sec (saxpy method) +tri+prep time: 0.000023 sec (incl time to compute L) +compute C time: 0.000015 sec reduce (C) time: 0.000001 sec -rate 8.47 million edges/sec (incl time for L=tril(A)) -rate 14.68 million edges/sec (just tricount itself) +rate 7.78 million edges/sec (incl time for L=tril(A)) +rate 10.86 million edges/sec (just tricount itself) -------------------------------------------------------------- matrix 4884 by 4884, 285494 entries, from stdin -total time to read A matrix: 0.070829 sec +total time to read A matrix: 0.070533 sec n 4884 # edges 142747 U=triu(A) time: 0.000237 sec -L=tril(A) time: 0.000214 sec +L=tril(A) time: 0.000177 sec ------------------------------------- dot product method: # triangles 1512964 -L*U' time (dot): 0.016448 sec -tricount time: 0.017444 sec (dot product method) -tri+prep time: 0.017895 sec (incl time to compute L and U) -compute C time: 0.016448 sec -reduce (C) time: 0.000995 sec -rate 7.98 million edges/sec (incl time for U=triu(A)) -rate 8.18 million edges/sec (just tricount itself) -L*U' time (dot): 0.007960 sec (nthreads: 2 speedup 2.06624) -tricount time: 0.009635 sec (dot product method) -tri+prep time: 0.010086 sec (incl time to compute L and U) -compute C time: 0.007960 sec -reduce (C) time: 0.001674 sec -rate 14.15 million edges/sec (incl time for U=triu(A)) -rate 14.82 million edges/sec (just tricount itself) -L*U' time (dot): 0.004200 sec (nthreads: 4 speedup 3.91649) -tricount time: 0.004743 sec (dot product method) -tri+prep time: 0.005194 sec (incl time to compute L and U) -compute C time: 0.004200 sec -reduce (C) time: 0.000543 sec -rate 27.48 million edges/sec (incl time for U=triu(A)) -rate 30.10 million edges/sec (just tricount itself) -L*U' time (dot): 0.009520 sec (nthreads: 8 speedup 1.72783) -tricount time: 0.010260 sec (dot product method) -tri+prep time: 0.010711 sec (incl time to compute L and U) -compute C time: 0.009520 sec -reduce (C) time: 0.000741 sec -rate 13.33 million edges/sec (incl time for U=triu(A)) -rate 13.91 million edges/sec (just tricount itself) -L*U' time (dot): 0.015530 sec -tricount time: 0.016475 sec (dot product method) -tri+prep time: 0.016926 sec (incl time to compute L and U) -compute C time: 0.015530 sec -reduce (C) time: 0.000945 sec -rate 8.43 million edges/sec (incl time for U=triu(A)) -rate 8.66 million edges/sec (just tricount itself) -L*U' time (dot): 0.008395 sec (nthreads: 2 speedup 1.84985) -tricount time: 0.008839 sec (dot product method) -tri+prep time: 0.009290 sec (incl time to compute L and U) -compute C time: 0.008395 sec -reduce (C) time: 0.000444 sec -rate 15.37 million edges/sec (incl time for U=triu(A)) -rate 16.15 million edges/sec (just tricount itself) -L*U' time (dot): 0.004378 sec (nthreads: 4 speedup 3.54732) -tricount time: 0.004727 sec (dot product method) -tri+prep time: 0.005179 sec (incl time to compute L and U) -compute C time: 0.004378 sec -reduce (C) time: 0.000349 sec -rate 27.56 million edges/sec (incl time for U=triu(A)) -rate 30.20 million edges/sec (just tricount itself) -L*U' time (dot): 0.005409 sec (nthreads: 8 speedup 2.87118) -tricount time: 0.005899 sec (dot product method) -tri+prep time: 0.006350 sec (incl time to compute L and U) -compute C time: 0.005409 sec -reduce (C) time: 0.000490 sec -rate 22.48 million edges/sec (incl time for U=triu(A)) -rate 24.20 million edges/sec (just tricount itself) +L*U' time (dot): 0.015604 sec +tricount time: 0.016610 sec (dot product method) +tri+prep time: 0.017023 sec (incl time to compute L and U) +compute C time: 0.015604 sec +reduce (C) time: 0.001006 sec +rate 8.39 million edges/sec (incl time for U=triu(A)) +rate 8.59 million edges/sec (just tricount itself) +L*U' time (dot): 0.007760 sec (nthreads: 2 speedup 2.01076) +tricount time: 0.008425 sec (dot product method) +tri+prep time: 0.008838 sec (incl time to compute L and U) +compute C time: 0.007760 sec +reduce (C) time: 0.000664 sec +rate 16.15 million edges/sec (incl time for U=triu(A)) +rate 16.94 million edges/sec (just tricount itself) +L*U' time (dot): 0.004202 sec (nthreads: 4 speedup 3.71338) +tricount time: 0.004798 sec (dot product method) +tri+prep time: 0.005212 sec (incl time to compute L and U) +compute C time: 0.004202 sec +reduce (C) time: 0.000596 sec +rate 27.39 million edges/sec (incl time for U=triu(A)) +rate 29.75 million edges/sec (just tricount itself) +L*U' time (dot): 0.002794 sec (nthreads: 8 speedup 5.58414) +tricount time: 0.003421 sec (dot product method) +tri+prep time: 0.003834 sec (incl time to compute L and U) +compute C time: 0.002794 sec +reduce (C) time: 0.000626 sec +rate 37.23 million edges/sec (incl time for U=triu(A)) +rate 41.73 million edges/sec (just tricount itself) +L*U' time (dot): 0.014963 sec +tricount time: 0.015630 sec (dot product method) +tri+prep time: 0.016043 sec (incl time to compute L and U) +compute C time: 0.014963 sec +reduce (C) time: 0.000667 sec +rate 8.90 million edges/sec (incl time for U=triu(A)) +rate 9.13 million edges/sec (just tricount itself) +L*U' time (dot): 0.007483 sec (nthreads: 2 speedup 1.99945) +tricount time: 0.007839 sec (dot product method) +tri+prep time: 0.008253 sec (incl time to compute L and U) +compute C time: 0.007483 sec +reduce (C) time: 0.000356 sec +rate 17.30 million edges/sec (incl time for U=triu(A)) +rate 18.21 million edges/sec (just tricount itself) +L*U' time (dot): 0.004180 sec (nthreads: 4 speedup 3.57986) +tricount time: 0.004810 sec (dot product method) +tri+prep time: 0.005223 sec (incl time to compute L and U) +compute C time: 0.004180 sec +reduce (C) time: 0.000630 sec +rate 27.33 million edges/sec (incl time for U=triu(A)) +rate 29.68 million edges/sec (just tricount itself) +L*U' time (dot): 0.002833 sec (nthreads: 8 speedup 5.28111) +tricount time: 0.003473 sec (dot product method) +tri+prep time: 0.003887 sec (incl time to compute L and U) +compute C time: 0.002833 sec +reduce (C) time: 0.000640 sec +rate 36.73 million edges/sec (incl time for U=triu(A)) +rate 41.10 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.011343 sec -tricount time: 0.011732 sec (saxpy method) -tri+prep time: 0.011946 sec (incl time to compute L) -compute C time: 0.011343 sec -reduce (C) time: 0.000390 sec -rate 11.95 million edges/sec (incl time for L=tril(A)) -rate 12.17 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.006111 sec (nthreads: 2 speedup 1.85609) -tricount time: 0.006302 sec (saxpy method) -tri+prep time: 0.006516 sec (incl time to compute L) -compute C time: 0.006111 sec -reduce (C) time: 0.000191 sec -rate 21.91 million edges/sec (incl time for L=tril(A)) -rate 22.65 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.003317 sec (nthreads: 4 speedup 3.4192) -tricount time: 0.003506 sec (saxpy method) -tri+prep time: 0.003720 sec (incl time to compute L) -compute C time: 0.003317 sec -reduce (C) time: 0.000189 sec -rate 38.37 million edges/sec (incl time for L=tril(A)) -rate 40.71 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.004551 sec (nthreads: 8 speedup 2.49242) -tricount time: 0.004741 sec (saxpy method) -tri+prep time: 0.004955 sec (incl time to compute L) -compute C time: 0.004551 sec -reduce (C) time: 0.000190 sec -rate 28.81 million edges/sec (incl time for L=tril(A)) -rate 30.11 million edges/sec (just tricount itself) +triangles, method 3: 1512964 +C=L*L time (saxpy): 0.013017 sec +tricount time: 0.013408 sec (saxpy method) +tri+prep time: 0.013585 sec (incl time to compute L) +compute C time: 0.013017 sec +reduce (C) time: 0.000392 sec +rate 10.51 million edges/sec (incl time for L=tril(A)) +rate 10.65 million edges/sec (just tricount itself) +triangles, method 3: 1512964 +C=L*L time (saxpy): 0.006626 sec (nthreads: 2 speedup 1.96461) +tricount time: 0.006824 sec (saxpy method) +tri+prep time: 0.007000 sec (incl time to compute L) +compute C time: 0.006626 sec +reduce (C) time: 0.000198 sec +rate 20.39 million edges/sec (incl time for L=tril(A)) +rate 20.92 million edges/sec (just tricount itself) +triangles, method 3: 1512964 +C=L*L time (saxpy): 0.004039 sec (nthreads: 4 speedup 3.22239) +tricount time: 0.004249 sec (saxpy method) +tri+prep time: 0.004426 sec (incl time to compute L) +compute C time: 0.004039 sec +reduce (C) time: 0.000210 sec +rate 32.25 million edges/sec (incl time for L=tril(A)) +rate 33.59 million edges/sec (just tricount itself) +triangles, method 3: 1512964 +C=L*L time (saxpy): 0.002870 sec (nthreads: 8 speedup 4.53567) +tricount time: 0.003111 sec (saxpy method) +tri+prep time: 0.003288 sec (incl time to compute L) +compute C time: 0.002870 sec +reduce (C) time: 0.000241 sec +rate 43.42 million edges/sec (incl time for L=tril(A)) +rate 45.88 million edges/sec (just tricount itself) -------------------------------------------------------------- matrix 183 by 183, 1402 entries, from stdin -total time to read A matrix: 0.000583 sec +total time to read A matrix: 0.000648 sec n 183 # edges 701 -U=triu(A) time: 0.000028 sec +U=triu(A) time: 0.000034 sec L=tril(A) time: 0.000010 sec ------------------------------------- dot product method: # triangles 863 -L*U' time (dot): 0.000061 sec -tricount time: 0.000073 sec (dot product method) -tri+prep time: 0.000111 sec (incl time to compute L and U) -compute C time: 0.000061 sec -reduce (C) time: 0.000012 sec -rate 6.32 million edges/sec (incl time for U=triu(A)) -rate 9.62 million edges/sec (just tricount itself) -L*U' time (dot): 0.000042 sec (nthreads: 2 speedup 1.46194) -tricount time: 0.000050 sec (dot product method) -tri+prep time: 0.000088 sec (incl time to compute L and U) -compute C time: 0.000042 sec -reduce (C) time: 0.000008 sec -rate 7.99 million edges/sec (incl time for U=triu(A)) -rate 14.11 million edges/sec (just tricount itself) -L*U' time (dot): 0.000038 sec (nthreads: 4 speedup 1.60703) -tricount time: 0.000045 sec (dot product method) -tri+prep time: 0.000083 sec (incl time to compute L and U) -compute C time: 0.000038 sec -reduce (C) time: 0.000007 sec -rate 8.44 million edges/sec (incl time for U=triu(A)) -rate 15.55 million edges/sec (just tricount itself) -L*U' time (dot): 0.000037 sec (nthreads: 8 speedup 1.66533) -tricount time: 0.000043 sec (dot product method) -tri+prep time: 0.000081 sec (incl time to compute L and U) -compute C time: 0.000037 sec -reduce (C) time: 0.000007 sec -rate 8.60 million edges/sec (incl time for U=triu(A)) -rate 16.12 million edges/sec (just tricount itself) -L*U' time (dot): 0.000048 sec -tricount time: 0.000055 sec (dot product method) -tri+prep time: 0.000093 sec (incl time to compute L and U) -compute C time: 0.000048 sec +L*U' time (dot): 0.000067 sec +tricount time: 0.000081 sec (dot product method) +tri+prep time: 0.000125 sec (incl time to compute L and U) +compute C time: 0.000067 sec +reduce (C) time: 0.000014 sec +rate 5.62 million edges/sec (incl time for U=triu(A)) +rate 8.68 million edges/sec (just tricount itself) +L*U' time (dot): 0.000041 sec (nthreads: 2 speedup 1.64645) +tricount time: 0.000048 sec (dot product method) +tri+prep time: 0.000092 sec (incl time to compute L and U) +compute C time: 0.000041 sec reduce (C) time: 0.000007 sec -rate 7.52 million edges/sec (incl time for U=triu(A)) -rate 12.70 million edges/sec (just tricount itself) -L*U' time (dot): 0.000043 sec (nthreads: 2 speedup 1.11068) -tricount time: 0.000050 sec (dot product method) +rate 7.60 million edges/sec (incl time for U=triu(A)) +rate 14.54 million edges/sec (just tricount itself) +L*U' time (dot): 0.000037 sec (nthreads: 4 speedup 1.80399) +tricount time: 0.000044 sec (dot product method) tri+prep time: 0.000088 sec (incl time to compute L and U) -compute C time: 0.000043 sec +compute C time: 0.000037 sec reduce (C) time: 0.000007 sec rate 7.96 million edges/sec (incl time for U=triu(A)) -rate 14.01 million edges/sec (just tricount itself) -L*U' time (dot): 0.000041 sec (nthreads: 4 speedup 1.17128) -tricount time: 0.000048 sec (dot product method) +rate 15.91 million edges/sec (just tricount itself) +L*U' time (dot): 0.000036 sec (nthreads: 8 speedup 1.86393) +tricount time: 0.000042 sec (dot product method) tri+prep time: 0.000086 sec (incl time to compute L and U) +compute C time: 0.000036 sec +reduce (C) time: 0.000006 sec +rate 8.12 million edges/sec (incl time for U=triu(A)) +rate 16.58 million edges/sec (just tricount itself) +L*U' time (dot): 0.000041 sec +tricount time: 0.000048 sec (dot product method) +tri+prep time: 0.000092 sec (incl time to compute L and U) compute C time: 0.000041 sec reduce (C) time: 0.000007 sec -rate 8.20 million edges/sec (incl time for U=triu(A)) -rate 14.75 million edges/sec (just tricount itself) -L*U' time (dot): 0.000038 sec (nthreads: 8 speedup 1.25408) -tricount time: 0.000044 sec (dot product method) -tri+prep time: 0.000082 sec (incl time to compute L and U) +rate 7.62 million edges/sec (incl time for U=triu(A)) +rate 14.61 million edges/sec (just tricount itself) +L*U' time (dot): 0.000038 sec (nthreads: 2 speedup 1.07256) +tricount time: 0.000045 sec (dot product method) +tri+prep time: 0.000089 sec (incl time to compute L and U) compute C time: 0.000038 sec +reduce (C) time: 0.000007 sec +rate 7.91 million edges/sec (incl time for U=triu(A)) +rate 15.69 million edges/sec (just tricount itself) +L*U' time (dot): 0.000036 sec (nthreads: 4 speedup 1.12909) +tricount time: 0.000042 sec (dot product method) +tri+prep time: 0.000086 sec (incl time to compute L and U) +compute C time: 0.000036 sec reduce (C) time: 0.000006 sec -rate 8.50 million edges/sec (incl time for U=triu(A)) -rate 15.77 million edges/sec (just tricount itself) +rate 8.11 million edges/sec (incl time for U=triu(A)) +rate 16.51 million edges/sec (just tricount itself) +L*U' time (dot): 0.000035 sec (nthreads: 8 speedup 1.15865) +tricount time: 0.000041 sec (dot product method) +tri+prep time: 0.000085 sec (incl time to compute L and U) +compute C time: 0.000035 sec +reduce (C) time: 0.000006 sec +rate 8.22 million edges/sec (incl time for U=triu(A)) +rate 16.99 million edges/sec (just tricount itself) + +----------------------------------- saxpy method: +triangles, method 3: 863 +C=L*L time (saxpy): 0.000055 sec +tricount time: 0.000056 sec (saxpy method) +tri+prep time: 0.000066 sec (incl time to compute L) +compute C time: 0.000055 sec +reduce (C) time: 0.000001 sec +rate 10.62 million edges/sec (incl time for L=tril(A)) +rate 12.41 million edges/sec (just tricount itself) +triangles, method 3: 863 +C=L*L time (saxpy): 0.000035 sec (nthreads: 2 speedup 1.57783) +tricount time: 0.000036 sec (saxpy method) +tri+prep time: 0.000046 sec (incl time to compute L) +compute C time: 0.000035 sec +reduce (C) time: 0.000001 sec +rate 15.33 million edges/sec (incl time for L=tril(A)) +rate 19.36 million edges/sec (just tricount itself) +triangles, method 3: 863 +C=L*L time (saxpy): 0.000032 sec (nthreads: 4 speedup 1.74196) +tricount time: 0.000033 sec (saxpy method) +tri+prep time: 0.000042 sec (incl time to compute L) +compute C time: 0.000032 sec +reduce (C) time: 0.000001 sec +rate 16.51 million edges/sec (incl time for L=tril(A)) +rate 21.29 million edges/sec (just tricount itself) +triangles, method 3: 863 +C=L*L time (saxpy): 0.000031 sec (nthreads: 8 speedup 1.78544) +tricount time: 0.000032 sec (saxpy method) +tri+prep time: 0.000042 sec (incl time to compute L) +compute C time: 0.000031 sec +reduce (C) time: 0.000001 sec +rate 16.75 million edges/sec (incl time for L=tril(A)) +rate 21.69 million edges/sec (just tricount itself) + +-------------------------------------------------------------- +matrix 63 by 63, 246 entries, from stdin + +total time to read A matrix: 0.000285 sec + +n 63 # edges 123 +U=triu(A) time: 0.000035 sec +L=tril(A) time: 0.000008 sec + +------------------------------------- dot product method: +# triangles 0 +L*U' time (dot): 0.000037 sec +tricount time: 0.000047 sec (dot product method) +tri+prep time: 0.000091 sec (incl time to compute L and U) +compute C time: 0.000037 sec +reduce (C) time: 0.000010 sec +rate 1.35 million edges/sec (incl time for U=triu(A)) +rate 2.61 million edges/sec (just tricount itself) +L*U' time (dot): 0.000005 sec (nthreads: 2 speedup 7.05837) +tricount time: 0.000009 sec (dot product method) +tri+prep time: 0.000053 sec (incl time to compute L and U) +compute C time: 0.000005 sec +reduce (C) time: 0.000004 sec +rate 2.31 million edges/sec (incl time for U=triu(A)) +rate 12.98 million edges/sec (just tricount itself) +L*U' time (dot): 0.000004 sec (nthreads: 4 speedup 9.18526) +tricount time: 0.000008 sec (dot product method) +tri+prep time: 0.000051 sec (incl time to compute L and U) +compute C time: 0.000004 sec +reduce (C) time: 0.000004 sec +rate 2.39 million edges/sec (incl time for U=triu(A)) +rate 16.02 million edges/sec (just tricount itself) +L*U' time (dot): 0.000006 sec (nthreads: 8 speedup 6.37217) +tricount time: 0.000010 sec (dot product method) +tri+prep time: 0.000054 sec (incl time to compute L and U) +compute C time: 0.000006 sec +reduce (C) time: 0.000004 sec +rate 2.28 million edges/sec (incl time for U=triu(A)) +rate 12.12 million edges/sec (just tricount itself) +L*U' time (dot): 0.000006 sec +tricount time: 0.000010 sec (dot product method) +tri+prep time: 0.000054 sec (incl time to compute L and U) +compute C time: 0.000006 sec +reduce (C) time: 0.000004 sec +rate 2.29 million edges/sec (incl time for U=triu(A)) +rate 12.29 million edges/sec (just tricount itself) +L*U' time (dot): 0.000004 sec (nthreads: 2 speedup 1.65) +tricount time: 0.000007 sec (dot product method) +tri+prep time: 0.000051 sec (incl time to compute L and U) +compute C time: 0.000004 sec +reduce (C) time: 0.000003 sec +rate 2.43 million edges/sec (incl time for U=triu(A)) +rate 18.14 million edges/sec (just tricount itself) +L*U' time (dot): 0.000006 sec (nthreads: 4 speedup 1.08933) +tricount time: 0.000010 sec (dot product method) +tri+prep time: 0.000054 sec (incl time to compute L and U) +compute C time: 0.000006 sec +reduce (C) time: 0.000005 sec +rate 2.27 million edges/sec (incl time for U=triu(A)) +rate 11.81 million edges/sec (just tricount itself) +L*U' time (dot): 0.000007 sec (nthreads: 8 speedup 0.944525) +tricount time: 0.000012 sec (dot product method) +tri+prep time: 0.000055 sec (incl time to compute L and U) +compute C time: 0.000007 sec +reduce (C) time: 0.000005 sec +rate 2.22 million edges/sec (incl time for U=triu(A)) +rate 10.53 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000044 sec -tricount time: 0.000046 sec (saxpy method) -tri+prep time: 0.000055 sec (incl time to compute L) -compute C time: 0.000044 sec +triangles, method 3: 0 +C=L*L time (saxpy): 0.000038 sec +tricount time: 0.000039 sec (saxpy method) +tri+prep time: 0.000048 sec (incl time to compute L) +compute C time: 0.000038 sec reduce (C) time: 0.000001 sec -rate 12.67 million edges/sec (incl time for L=tril(A)) -rate 15.36 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000034 sec (nthreads: 2 speedup 1.30181) -tricount time: 0.000035 sec (saxpy method) -tri+prep time: 0.000045 sec (incl time to compute L) -compute C time: 0.000034 sec +rate 2.59 million edges/sec (incl time for L=tril(A)) +rate 3.15 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000018 sec (nthreads: 2 speedup 2.11677) +tricount time: 0.000019 sec (saxpy method) +tri+prep time: 0.000027 sec (incl time to compute L) +compute C time: 0.000018 sec reduce (C) time: 0.000001 sec -rate 15.60 million edges/sec (incl time for L=tril(A)) -rate 19.89 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000031 sec (nthreads: 4 speedup 1.4348) -tricount time: 0.000032 sec (saxpy method) -tri+prep time: 0.000042 sec (incl time to compute L) -compute C time: 0.000031 sec +rate 4.52 million edges/sec (incl time for L=tril(A)) +rate 6.55 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000018 sec (nthreads: 4 speedup 2.10611) +tricount time: 0.000019 sec (saxpy method) +tri+prep time: 0.000027 sec (incl time to compute L) +compute C time: 0.000018 sec reduce (C) time: 0.000001 sec -rate 16.79 million edges/sec (incl time for L=tril(A)) -rate 21.86 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000030 sec (nthreads: 8 speedup 1.46692) +rate 4.52 million edges/sec (incl time for L=tril(A)) +rate 6.55 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000030 sec (nthreads: 8 speedup 1.2624) tricount time: 0.000031 sec (saxpy method) -tri+prep time: 0.000041 sec (incl time to compute L) +tri+prep time: 0.000039 sec (incl time to compute L) compute C time: 0.000030 sec reduce (C) time: 0.000001 sec -rate 17.03 million edges/sec (incl time for L=tril(A)) -rate 22.28 million edges/sec (just tricount itself) +rate 3.12 million edges/sec (incl time for L=tril(A)) +rate 3.97 million edges/sec (just tricount itself) -------------------------------------------------------------- matrix 63 by 63, 246 entries, from stdin -total time to read A matrix: 0.000168 sec +total time to read A matrix: 0.000222 sec n 63 # edges 123 -U=triu(A) time: 0.000016 sec -L=tril(A) time: 0.000004 sec +U=triu(A) time: 0.000024 sec +L=tril(A) time: 0.000005 sec ------------------------------------- dot product method: # triangles 0 -L*U' time (dot): 0.000016 sec -tricount time: 0.000022 sec (dot product method) -tri+prep time: 0.000042 sec (incl time to compute L and U) -compute C time: 0.000016 sec -reduce (C) time: 0.000006 sec -rate 2.90 million edges/sec (incl time for U=triu(A)) -rate 5.52 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 2 speedup 3.74828) +L*U' time (dot): 0.000030 sec +tricount time: 0.000037 sec (dot product method) +tri+prep time: 0.000067 sec (incl time to compute L and U) +compute C time: 0.000030 sec +reduce (C) time: 0.000008 sec +rate 1.84 million edges/sec (incl time for U=triu(A)) +rate 3.28 million edges/sec (just tricount itself) +L*U' time (dot): 0.000005 sec (nthreads: 2 speedup 6.03715) tricount time: 0.000008 sec (dot product method) -tri+prep time: 0.000028 sec (incl time to compute L and U) -compute C time: 0.000004 sec +tri+prep time: 0.000038 sec (incl time to compute L and U) +compute C time: 0.000005 sec reduce (C) time: 0.000003 sec -rate 4.43 million edges/sec (incl time for U=triu(A)) -rate 16.19 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 4 speedup 4.66372) +rate 3.26 million edges/sec (incl time for U=triu(A)) +rate 14.95 million edges/sec (just tricount itself) +L*U' time (dot): 0.000004 sec (nthreads: 4 speedup 7.86954) tricount time: 0.000007 sec (dot product method) -tri+prep time: 0.000027 sec (incl time to compute L and U) +tri+prep time: 0.000037 sec (incl time to compute L and U) compute C time: 0.000004 sec reduce (C) time: 0.000003 sec -rate 4.56 million edges/sec (incl time for U=triu(A)) -rate 18.14 million edges/sec (just tricount itself) -L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 4.82743) +rate 3.36 million edges/sec (incl time for U=triu(A)) +rate 17.25 million edges/sec (just tricount itself) +L*U' time (dot): 0.000004 sec (nthreads: 8 speedup 8.28384) tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000026 sec (incl time to compute L and U) -compute C time: 0.000003 sec +tri+prep time: 0.000036 sec (incl time to compute L and U) +compute C time: 0.000004 sec reduce (C) time: 0.000003 sec -rate 4.70 million edges/sec (incl time for U=triu(A)) -rate 20.55 million edges/sec (just tricount itself) +rate 3.45 million edges/sec (incl time for U=triu(A)) +rate 19.84 million edges/sec (just tricount itself) L*U' time (dot): 0.000004 sec tricount time: 0.000007 sec (dot product method) -tri+prep time: 0.000027 sec (incl time to compute L and U) +tri+prep time: 0.000037 sec (incl time to compute L and U) compute C time: 0.000004 sec reduce (C) time: 0.000003 sec -rate 4.53 million edges/sec (incl time for U=triu(A)) -rate 17.55 million edges/sec (just tricount itself) -L*U' time (dot): 0.000003 sec (nthreads: 2 speedup 1.17227) -tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000026 sec (incl time to compute L and U) -compute C time: 0.000003 sec +rate 3.35 million edges/sec (incl time for U=triu(A)) +rate 17.09 million edges/sec (just tricount itself) +L*U' time (dot): 0.000004 sec (nthreads: 2 speedup 1.06995) +tricount time: 0.000007 sec (dot product method) +tri+prep time: 0.000036 sec (incl time to compute L and U) +compute C time: 0.000004 sec reduce (C) time: 0.000003 sec -rate 4.64 million edges/sec (incl time for U=triu(A)) -rate 19.46 million edges/sec (just tricount itself) -L*U' time (dot): 0.000003 sec (nthreads: 4 speedup 1.1764) +rate 3.37 million edges/sec (incl time for U=triu(A)) +rate 17.57 million edges/sec (just tricount itself) +L*U' time (dot): 0.000004 sec (nthreads: 4 speedup 1.17271) tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000026 sec (incl time to compute L and U) -compute C time: 0.000003 sec -reduce (C) time: 0.000002 sec -rate 4.73 million edges/sec (incl time for U=triu(A)) -rate 21.10 million edges/sec (just tricount itself) -L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 1.22307) +tri+prep time: 0.000036 sec (incl time to compute L and U) +compute C time: 0.000004 sec +reduce (C) time: 0.000003 sec +rate 3.46 million edges/sec (incl time for U=triu(A)) +rate 20.24 million edges/sec (just tricount itself) +L*U' time (dot): 0.000004 sec (nthreads: 8 speedup 1.19076) tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000026 sec (incl time to compute L and U) -compute C time: 0.000003 sec +tri+prep time: 0.000035 sec (incl time to compute L and U) +compute C time: 0.000004 sec reduce (C) time: 0.000002 sec -rate 4.76 million edges/sec (incl time for U=triu(A)) -rate 21.74 million edges/sec (just tricount itself) +rate 3.47 million edges/sec (incl time for U=triu(A)) +rate 20.68 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000020 sec -tricount time: 0.000020 sec (saxpy method) -tri+prep time: 0.000025 sec (incl time to compute L) -compute C time: 0.000020 sec +triangles, method 3: 0 +C=L*L time (saxpy): 0.000021 sec +tricount time: 0.000022 sec (saxpy method) +tri+prep time: 0.000027 sec (incl time to compute L) +compute C time: 0.000021 sec reduce (C) time: 0.000000 sec -rate 4.97 million edges/sec (incl time for L=tril(A)) -rate 6.07 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000012 sec (nthreads: 2 speedup 1.68975) +rate 4.63 million edges/sec (incl time for L=tril(A)) +rate 5.69 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000012 sec (nthreads: 2 speedup 1.768) tricount time: 0.000012 sec (saxpy method) tri+prep time: 0.000017 sec (incl time to compute L) compute C time: 0.000012 sec reduce (C) time: 0.000000 sec -rate 7.44 million edges/sec (incl time for L=tril(A)) -rate 10.22 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000013 sec (nthreads: 4 speedup 1.59131) +rate 7.09 million edges/sec (incl time for L=tril(A)) +rate 9.95 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000011 sec (nthreads: 4 speedup 1.90467) +tricount time: 0.000012 sec (saxpy method) +tri+prep time: 0.000016 sec (incl time to compute L) +compute C time: 0.000011 sec +reduce (C) time: 0.000000 sec +rate 7.46 million edges/sec (incl time for L=tril(A)) +rate 10.69 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000013 sec (nthreads: 8 speedup 1.69722) tricount time: 0.000013 sec (saxpy method) -tri+prep time: 0.000017 sec (incl time to compute L) +tri+prep time: 0.000018 sec (incl time to compute L) compute C time: 0.000013 sec reduce (C) time: 0.000000 sec -rate 7.13 million edges/sec (incl time for L=tril(A)) -rate 9.63 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000017 sec (nthreads: 8 speedup 1.18573) -tricount time: 0.000017 sec (saxpy method) -tri+prep time: 0.000022 sec (incl time to compute L) -compute C time: 0.000017 sec -reduce (C) time: 0.000000 sec -rate 5.69 million edges/sec (incl time for L=tril(A)) -rate 7.19 million edges/sec (just tricount itself) - --------------------------------------------------------------- -matrix 63 by 63, 246 entries, from stdin - -total time to read A matrix: 0.000170 sec - -n 63 # edges 123 -U=triu(A) time: 0.000021 sec -L=tril(A) time: 0.000005 sec - -------------------------------------- dot product method: -# triangles 0 -L*U' time (dot): 0.000016 sec -tricount time: 0.000022 sec (dot product method) -tri+prep time: 0.000048 sec (incl time to compute L and U) -compute C time: 0.000016 sec -reduce (C) time: 0.000006 sec -rate 2.59 million edges/sec (incl time for U=triu(A)) -rate 5.63 million edges/sec (just tricount itself) -L*U' time (dot): 0.000007 sec (nthreads: 2 speedup 2.38811) -tricount time: 0.000012 sec (dot product method) -tri+prep time: 0.000038 sec (incl time to compute L and U) -compute C time: 0.000007 sec -reduce (C) time: 0.000005 sec -rate 3.27 million edges/sec (incl time for U=triu(A)) -rate 10.33 million edges/sec (just tricount itself) -L*U' time (dot): 0.000007 sec (nthreads: 4 speedup 2.43022) -tricount time: 0.000012 sec (dot product method) -tri+prep time: 0.000037 sec (incl time to compute L and U) -compute C time: 0.000007 sec -reduce (C) time: 0.000005 sec -rate 3.28 million edges/sec (incl time for U=triu(A)) -rate 10.43 million edges/sec (just tricount itself) -L*U' time (dot): 0.000006 sec (nthreads: 8 speedup 2.53585) -tricount time: 0.000011 sec (dot product method) -tri+prep time: 0.000037 sec (incl time to compute L and U) -compute C time: 0.000006 sec -reduce (C) time: 0.000005 sec -rate 3.36 million edges/sec (incl time for U=triu(A)) -rate 11.28 million edges/sec (just tricount itself) -L*U' time (dot): 0.000007 sec -tricount time: 0.000012 sec (dot product method) -tri+prep time: 0.000037 sec (incl time to compute L and U) -compute C time: 0.000007 sec -reduce (C) time: 0.000005 sec -rate 3.28 million edges/sec (incl time for U=triu(A)) -rate 10.40 million edges/sec (just tricount itself) -L*U' time (dot): 0.000006 sec (nthreads: 2 speedup 1.13474) -tricount time: 0.000011 sec (dot product method) -tri+prep time: 0.000036 sec (incl time to compute L and U) -compute C time: 0.000006 sec -reduce (C) time: 0.000005 sec -rate 3.38 million edges/sec (incl time for U=triu(A)) -rate 11.43 million edges/sec (just tricount itself) -L*U' time (dot): 0.000006 sec (nthreads: 4 speedup 1.07643) -tricount time: 0.000011 sec (dot product method) -tri+prep time: 0.000037 sec (incl time to compute L and U) -compute C time: 0.000006 sec -reduce (C) time: 0.000005 sec -rate 3.34 million edges/sec (incl time for U=triu(A)) -rate 11.04 million edges/sec (just tricount itself) -L*U' time (dot): 0.000006 sec (nthreads: 8 speedup 1.1264) -tricount time: 0.000011 sec (dot product method) -tri+prep time: 0.000036 sec (incl time to compute L and U) -compute C time: 0.000006 sec -reduce (C) time: 0.000005 sec -rate 3.38 million edges/sec (incl time for U=triu(A)) -rate 11.45 million edges/sec (just tricount itself) - ------------------------------------ saxpy method: -C=L*L time (saxpy): 0.000023 sec -tricount time: 0.000023 sec (saxpy method) -tri+prep time: 0.000028 sec (incl time to compute L) -compute C time: 0.000023 sec -reduce (C) time: 0.000000 sec -rate 4.39 million edges/sec (incl time for L=tril(A)) -rate 5.29 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000018 sec (nthreads: 2 speedup 1.27137) -tricount time: 0.000018 sec (saxpy method) -tri+prep time: 0.000023 sec (incl time to compute L) -compute C time: 0.000018 sec -reduce (C) time: 0.000000 sec -rate 5.33 million edges/sec (incl time for L=tril(A)) -rate 6.73 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000018 sec (nthreads: 4 speedup 1.29131) -tricount time: 0.000018 sec (saxpy method) -tri+prep time: 0.000023 sec (incl time to compute L) -compute C time: 0.000018 sec -reduce (C) time: 0.000000 sec -rate 5.39 million edges/sec (incl time for L=tril(A)) -rate 6.83 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000020 sec (nthreads: 8 speedup 1.1211) -tricount time: 0.000021 sec (saxpy method) -tri+prep time: 0.000026 sec (incl time to compute L) -compute C time: 0.000020 sec -reduce (C) time: 0.000000 sec -rate 4.82 million edges/sec (incl time for L=tril(A)) -rate 5.93 million edges/sec (just tricount itself) +rate 6.88 million edges/sec (incl time for L=tril(A)) +rate 9.53 million edges/sec (just tricount itself) -------------------------------------------------------------- matrix 78 by 78, 204 entries, from stdin -total time to read A matrix: 0.000157 sec +total time to read A matrix: 0.000178 sec n 78 # edges 102 -U=triu(A) time: 0.000015 sec -L=tril(A) time: 0.000005 sec +U=triu(A) time: 0.000021 sec +L=tril(A) time: 0.000006 sec ------------------------------------- dot product method: # triangles 0 -L*U' time (dot): 0.000021 sec -tricount time: 0.000026 sec (dot product method) -tri+prep time: 0.000047 sec (incl time to compute L and U) -compute C time: 0.000021 sec -reduce (C) time: 0.000006 sec -rate 2.19 million edges/sec (incl time for U=triu(A)) -rate 3.88 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 2 speedup 4.80607) -tricount time: 0.000008 sec (dot product method) -tri+prep time: 0.000028 sec (incl time to compute L and U) -compute C time: 0.000004 sec -reduce (C) time: 0.000003 sec -rate 3.65 million edges/sec (incl time for U=triu(A)) -rate 13.29 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec (nthreads: 4 speedup 5.43748) +L*U' time (dot): 0.000031 sec +tricount time: 0.000038 sec (dot product method) +tri+prep time: 0.000066 sec (incl time to compute L and U) +compute C time: 0.000031 sec +reduce (C) time: 0.000008 sec +rate 1.55 million edges/sec (incl time for U=triu(A)) +rate 2.66 million edges/sec (just tricount itself) +L*U' time (dot): 0.000005 sec (nthreads: 2 speedup 5.82485) +tricount time: 0.000009 sec (dot product method) +tri+prep time: 0.000036 sec (incl time to compute L and U) +compute C time: 0.000005 sec +reduce (C) time: 0.000004 sec +rate 2.81 million edges/sec (incl time for U=triu(A)) +rate 11.53 million edges/sec (just tricount itself) +L*U' time (dot): 0.000004 sec (nthreads: 4 speedup 7.9056) tricount time: 0.000007 sec (dot product method) -tri+prep time: 0.000027 sec (incl time to compute L and U) +tri+prep time: 0.000034 sec (incl time to compute L and U) compute C time: 0.000004 sec reduce (C) time: 0.000003 sec -rate 3.79 million edges/sec (incl time for U=triu(A)) -rate 15.37 million edges/sec (just tricount itself) -L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 6.34682) -tricount time: 0.000007 sec (dot product method) -tri+prep time: 0.000027 sec (incl time to compute L and U) +rate 2.99 million edges/sec (incl time for U=triu(A)) +rate 15.34 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 9.02629) +tricount time: 0.000008 sec (dot product method) +tri+prep time: 0.000035 sec (incl time to compute L and U) compute C time: 0.000003 sec +reduce (C) time: 0.000005 sec +rate 2.88 million edges/sec (incl time for U=triu(A)) +rate 12.84 million edges/sec (just tricount itself) +L*U' time (dot): 0.000006 sec +tricount time: 0.000010 sec (dot product method) +tri+prep time: 0.000037 sec (incl time to compute L and U) +compute C time: 0.000006 sec reduce (C) time: 0.000004 sec -rate 3.74 million edges/sec (incl time for U=triu(A)) -rate 14.49 million edges/sec (just tricount itself) -L*U' time (dot): 0.000004 sec +rate 2.76 million edges/sec (incl time for U=triu(A)) +rate 10.69 million edges/sec (just tricount itself) +L*U' time (dot): 0.000004 sec (nthreads: 2 speedup 1.45911) tricount time: 0.000007 sec (dot product method) -tri+prep time: 0.000028 sec (incl time to compute L and U) +tri+prep time: 0.000034 sec (incl time to compute L and U) compute C time: 0.000004 sec reduce (C) time: 0.000003 sec -rate 3.70 million edges/sec (incl time for U=triu(A)) -rate 13.98 million edges/sec (just tricount itself) -L*U' time (dot): 0.000003 sec (nthreads: 2 speedup 1.15271) -tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000027 sec (incl time to compute L and U) -compute C time: 0.000003 sec -reduce (C) time: 0.000003 sec -rate 3.83 million edges/sec (incl time for U=triu(A)) -rate 16.06 million edges/sec (just tricount itself) -L*U' time (dot): 0.000003 sec (nthreads: 4 speedup 1.14478) +rate 2.98 million edges/sec (incl time for U=triu(A)) +rate 15.00 million edges/sec (just tricount itself) +L*U' time (dot): 0.000004 sec (nthreads: 4 speedup 1.47275) tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000026 sec (incl time to compute L and U) -compute C time: 0.000003 sec +tri+prep time: 0.000034 sec (incl time to compute L and U) +compute C time: 0.000004 sec reduce (C) time: 0.000003 sec -rate 3.87 million edges/sec (incl time for U=triu(A)) -rate 16.79 million edges/sec (just tricount itself) -L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 1.13797) +rate 3.01 million edges/sec (incl time for U=triu(A)) +rate 15.96 million edges/sec (just tricount itself) +L*U' time (dot): 0.000003 sec (nthreads: 8 speedup 1.66235) tricount time: 0.000006 sec (dot product method) -tri+prep time: 0.000026 sec (incl time to compute L and U) +tri+prep time: 0.000033 sec (incl time to compute L and U) compute C time: 0.000003 sec -reduce (C) time: 0.000003 sec -rate 3.87 million edges/sec (incl time for U=triu(A)) -rate 16.68 million edges/sec (just tricount itself) +reduce (C) time: 0.000002 sec +rate 3.07 million edges/sec (incl time for U=triu(A)) +rate 17.70 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000019 sec -tricount time: 0.000019 sec (saxpy method) -tri+prep time: 0.000024 sec (incl time to compute L) -compute C time: 0.000019 sec -reduce (C) time: 0.000000 sec -rate 4.28 million edges/sec (incl time for L=tril(A)) -rate 5.35 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000012 sec (nthreads: 2 speedup 1.51135) -tricount time: 0.000013 sec (saxpy method) -tri+prep time: 0.000017 sec (incl time to compute L) -compute C time: 0.000012 sec -reduce (C) time: 0.000000 sec -rate 5.86 million edges/sec (incl time for L=tril(A)) -rate 8.08 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000013 sec (nthreads: 4 speedup 1.43971) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000030 sec +tricount time: 0.000030 sec (saxpy method) +tri+prep time: 0.000037 sec (incl time to compute L) +compute C time: 0.000030 sec +reduce (C) time: 0.000001 sec +rate 2.77 million edges/sec (incl time for L=tril(A)) +rate 3.36 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000013 sec (nthreads: 2 speedup 2.37011) tricount time: 0.000013 sec (saxpy method) -tri+prep time: 0.000018 sec (incl time to compute L) +tri+prep time: 0.000019 sec (incl time to compute L) compute C time: 0.000013 sec reduce (C) time: 0.000000 sec -rate 5.66 million edges/sec (incl time for L=tril(A)) -rate 7.70 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000025 sec (nthreads: 8 speedup 0.737911) +rate 5.29 million edges/sec (incl time for L=tril(A)) +rate 7.92 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000013 sec (nthreads: 4 speedup 2.26979) +tricount time: 0.000014 sec (saxpy method) +tri+prep time: 0.000020 sec (incl time to compute L) +compute C time: 0.000013 sec +reduce (C) time: 0.000001 sec +rate 5.06 million edges/sec (incl time for L=tril(A)) +rate 7.41 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000026 sec (nthreads: 8 speedup 1.16697) tricount time: 0.000026 sec (saxpy method) -tri+prep time: 0.000030 sec (incl time to compute L) -compute C time: 0.000025 sec -reduce (C) time: 0.000000 sec -rate 3.35 million edges/sec (incl time for L=tril(A)) -rate 3.97 million edges/sec (just tricount itself) +tri+prep time: 0.000033 sec (incl time to compute L) +compute C time: 0.000026 sec +reduce (C) time: 0.000001 sec +rate 3.13 million edges/sec (incl time for L=tril(A)) +rate 3.89 million edges/sec (just tricount itself) -------------------------------------------------------------- matrix 982 by 982, 99840 entries, from stdin -total time to read A matrix: 0.026821 sec +total time to read A matrix: 0.027242 sec n 982 # edges 49920 -U=triu(A) time: 0.000158 sec -L=tril(A) time: 0.000129 sec +U=triu(A) time: 0.000163 sec +L=tril(A) time: 0.000136 sec ------------------------------------- dot product method: # triangles 0 -L*U' time (dot): 0.000394 sec -tricount time: 0.000486 sec (dot product method) -tri+prep time: 0.000774 sec (incl time to compute L and U) -compute C time: 0.000394 sec -reduce (C) time: 0.000092 sec -rate 64.51 million edges/sec (incl time for U=triu(A)) -rate 102.66 million edges/sec (just tricount itself) -L*U' time (dot): 0.000377 sec (nthreads: 2 speedup 1.04644) -tricount time: 0.000466 sec (dot product method) -tri+prep time: 0.000754 sec (incl time to compute L and U) -compute C time: 0.000377 sec -reduce (C) time: 0.000089 sec -rate 66.22 million edges/sec (incl time for U=triu(A)) -rate 107.08 million edges/sec (just tricount itself) -L*U' time (dot): 0.000313 sec (nthreads: 4 speedup 1.26114) -tricount time: 0.000402 sec (dot product method) -tri+prep time: 0.000689 sec (incl time to compute L and U) -compute C time: 0.000313 sec -reduce (C) time: 0.000089 sec -rate 72.41 million edges/sec (incl time for U=triu(A)) -rate 124.26 million edges/sec (just tricount itself) -L*U' time (dot): 0.000290 sec (nthreads: 8 speedup 1.35934) -tricount time: 0.000417 sec (dot product method) -tri+prep time: 0.000705 sec (incl time to compute L and U) -compute C time: 0.000290 sec -reduce (C) time: 0.000127 sec -rate 70.85 million edges/sec (incl time for U=triu(A)) -rate 119.74 million edges/sec (just tricount itself) -L*U' time (dot): 0.000431 sec -tricount time: 0.000554 sec (dot product method) -tri+prep time: 0.000842 sec (incl time to compute L and U) -compute C time: 0.000431 sec -reduce (C) time: 0.000123 sec -rate 59.32 million edges/sec (incl time for U=triu(A)) -rate 90.13 million edges/sec (just tricount itself) -L*U' time (dot): 0.000338 sec (nthreads: 2 speedup 1.2737) -tricount time: 0.000428 sec (dot product method) -tri+prep time: 0.000715 sec (incl time to compute L and U) -compute C time: 0.000338 sec -reduce (C) time: 0.000089 sec -rate 69.78 million edges/sec (incl time for U=triu(A)) -rate 116.70 million edges/sec (just tricount itself) -L*U' time (dot): 0.000297 sec (nthreads: 4 speedup 1.45141) -tricount time: 0.000385 sec (dot product method) -tri+prep time: 0.000672 sec (incl time to compute L and U) -compute C time: 0.000297 sec -reduce (C) time: 0.000088 sec -rate 74.26 million edges/sec (incl time for U=triu(A)) -rate 129.79 million edges/sec (just tricount itself) -L*U' time (dot): 0.005728 sec (nthreads: 8 speedup 0.0752694) -tricount time: 0.005857 sec (dot product method) -tri+prep time: 0.006144 sec (incl time to compute L and U) -compute C time: 0.005728 sec -reduce (C) time: 0.000129 sec -rate 8.12 million edges/sec (incl time for U=triu(A)) -rate 8.52 million edges/sec (just tricount itself) +L*U' time (dot): 0.000341 sec +tricount time: 0.000413 sec (dot product method) +tri+prep time: 0.000711 sec (incl time to compute L and U) +compute C time: 0.000341 sec +reduce (C) time: 0.000072 sec +rate 70.16 million edges/sec (incl time for U=triu(A)) +rate 120.85 million edges/sec (just tricount itself) +L*U' time (dot): 0.000306 sec (nthreads: 2 speedup 1.11459) +tricount time: 0.000369 sec (dot product method) +tri+prep time: 0.000668 sec (incl time to compute L and U) +compute C time: 0.000306 sec +reduce (C) time: 0.000064 sec +rate 74.75 million edges/sec (incl time for U=triu(A)) +rate 135.12 million edges/sec (just tricount itself) +L*U' time (dot): 0.000250 sec (nthreads: 4 speedup 1.36541) +tricount time: 0.000314 sec (dot product method) +tri+prep time: 0.000613 sec (incl time to compute L and U) +compute C time: 0.000250 sec +reduce (C) time: 0.000065 sec +rate 81.48 million edges/sec (incl time for U=triu(A)) +rate 158.86 million edges/sec (just tricount itself) +L*U' time (dot): 0.001259 sec (nthreads: 8 speedup 0.270668) +tricount time: 0.001334 sec (dot product method) +tri+prep time: 0.001632 sec (incl time to compute L and U) +compute C time: 0.001259 sec +reduce (C) time: 0.000075 sec +rate 30.58 million edges/sec (incl time for U=triu(A)) +rate 37.42 million edges/sec (just tricount itself) +L*U' time (dot): 0.000366 sec +tricount time: 0.000436 sec (dot product method) +tri+prep time: 0.000734 sec (incl time to compute L and U) +compute C time: 0.000366 sec +reduce (C) time: 0.000070 sec +rate 67.98 million edges/sec (incl time for U=triu(A)) +rate 114.50 million edges/sec (just tricount itself) +L*U' time (dot): 0.000291 sec (nthreads: 2 speedup 1.2581) +tricount time: 0.000355 sec (dot product method) +tri+prep time: 0.000654 sec (incl time to compute L and U) +compute C time: 0.000291 sec +reduce (C) time: 0.000064 sec +rate 76.36 million edges/sec (incl time for U=triu(A)) +rate 140.49 million edges/sec (just tricount itself) +L*U' time (dot): 0.000247 sec (nthreads: 4 speedup 1.4854) +tricount time: 0.000319 sec (dot product method) +tri+prep time: 0.000617 sec (incl time to compute L and U) +compute C time: 0.000247 sec +reduce (C) time: 0.000072 sec +rate 80.90 million edges/sec (incl time for U=triu(A)) +rate 156.64 million edges/sec (just tricount itself) +L*U' time (dot): 0.002759 sec (nthreads: 8 speedup 0.132738) +tricount time: 0.002832 sec (dot product method) +tri+prep time: 0.003130 sec (incl time to compute L and U) +compute C time: 0.002759 sec +reduce (C) time: 0.000073 sec +rate 15.95 million edges/sec (incl time for U=triu(A)) +rate 17.63 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000281 sec -tricount time: 0.000282 sec (saxpy method) -tri+prep time: 0.000411 sec (incl time to compute L) -compute C time: 0.000281 sec +triangles, method 3: 0 +C=L*L time (saxpy): 0.000248 sec +tricount time: 0.000248 sec (saxpy method) +tri+prep time: 0.000384 sec (incl time to compute L) +compute C time: 0.000248 sec reduce (C) time: 0.000001 sec -rate 121.51 million edges/sec (incl time for L=tril(A)) -rate 177.33 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000272 sec (nthreads: 2 speedup 1.03328) -tricount time: 0.000272 sec (saxpy method) -tri+prep time: 0.000402 sec (incl time to compute L) -compute C time: 0.000272 sec +rate 130.04 million edges/sec (incl time for L=tril(A)) +rate 200.99 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000232 sec (nthreads: 2 speedup 1.06781) +tricount time: 0.000233 sec (saxpy method) +tri+prep time: 0.000368 sec (incl time to compute L) +compute C time: 0.000232 sec reduce (C) time: 0.000001 sec -rate 124.28 million edges/sec (incl time for L=tril(A)) -rate 183.31 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000196 sec (nthreads: 4 speedup 1.43261) -tricount time: 0.000197 sec (saxpy method) -tri+prep time: 0.000326 sec (incl time to compute L) -compute C time: 0.000196 sec +rate 135.59 million edges/sec (incl time for L=tril(A)) +rate 214.58 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000231 sec (nthreads: 4 speedup 1.07507) +tricount time: 0.000231 sec (saxpy method) +tri+prep time: 0.000367 sec (incl time to compute L) +compute C time: 0.000231 sec reduce (C) time: 0.000001 sec -rate 153.13 million edges/sec (incl time for L=tril(A)) -rate 253.85 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000191 sec (nthreads: 8 speedup 1.4685) -tricount time: 0.000192 sec (saxpy method) -tri+prep time: 0.000321 sec (incl time to compute L) -compute C time: 0.000191 sec +rate 136.18 million edges/sec (incl time for L=tril(A)) +rate 216.05 million edges/sec (just tricount itself) +triangles, method 3: 0 +C=L*L time (saxpy): 0.000232 sec (nthreads: 8 speedup 1.06746) +tricount time: 0.000233 sec (saxpy method) +tri+prep time: 0.000368 sec (incl time to compute L) +compute C time: 0.000232 sec reduce (C) time: 0.000001 sec -rate 155.53 million edges/sec (incl time for L=tril(A)) -rate 260.51 million edges/sec (just tricount itself) +rate 135.55 million edges/sec (incl time for L=tril(A)) +rate 214.48 million edges/sec (just tricount itself) -------------------------------------------------------------- matrix 67 by 67, 574 entries, from stdin -total time to read A matrix: 0.000263 sec +total time to read A matrix: 0.000244 sec n 67 # edges 287 -U=triu(A) time: 0.000029 sec +U=triu(A) time: 0.000023 sec L=tril(A) time: 0.000007 sec ------------------------------------- dot product method: # triangles 120 -L*U' time (dot): 0.000037 sec -tricount time: 0.000047 sec (dot product method) -tri+prep time: 0.000083 sec (incl time to compute L and U) -compute C time: 0.000037 sec -reduce (C) time: 0.000009 sec -rate 3.46 million edges/sec (incl time for U=triu(A)) -rate 6.16 million edges/sec (just tricount itself) -L*U' time (dot): 0.000012 sec (nthreads: 2 speedup 3.08711) +L*U' time (dot): 0.000029 sec +tricount time: 0.000036 sec (dot product method) +tri+prep time: 0.000066 sec (incl time to compute L and U) +compute C time: 0.000029 sec +reduce (C) time: 0.000007 sec +rate 4.35 million edges/sec (incl time for U=triu(A)) +rate 7.90 million edges/sec (just tricount itself) +L*U' time (dot): 0.000012 sec (nthreads: 2 speedup 2.40315) tricount time: 0.000016 sec (dot product method) -tri+prep time: 0.000053 sec (incl time to compute L and U) +tri+prep time: 0.000046 sec (incl time to compute L and U) compute C time: 0.000012 sec reduce (C) time: 0.000004 sec -rate 5.46 million edges/sec (incl time for U=triu(A)) -rate 17.74 million edges/sec (just tricount itself) -L*U' time (dot): 0.000010 sec (nthreads: 4 speedup 3.72583) +rate 6.29 million edges/sec (incl time for U=triu(A)) +rate 18.03 million edges/sec (just tricount itself) +L*U' time (dot): 0.000010 sec (nthreads: 4 speedup 2.98421) tricount time: 0.000013 sec (dot product method) -tri+prep time: 0.000050 sec (incl time to compute L and U) +tri+prep time: 0.000043 sec (incl time to compute L and U) compute C time: 0.000010 sec reduce (C) time: 0.000003 sec -rate 5.78 million edges/sec (incl time for U=triu(A)) -rate 21.63 million edges/sec (just tricount itself) -L*U' time (dot): 0.000009 sec (nthreads: 8 speedup 4.15757) -tricount time: 0.000013 sec (dot product method) -tri+prep time: 0.000049 sec (incl time to compute L and U) +rate 6.69 million edges/sec (incl time for U=triu(A)) +rate 21.80 million edges/sec (just tricount itself) +L*U' time (dot): 0.000009 sec (nthreads: 8 speedup 3.27907) +tricount time: 0.000012 sec (dot product method) +tri+prep time: 0.000042 sec (incl time to compute L and U) compute C time: 0.000009 sec reduce (C) time: 0.000003 sec -rate 5.87 million edges/sec (incl time for U=triu(A)) -rate 22.94 million edges/sec (just tricount itself) -L*U' time (dot): 0.000014 sec -tricount time: 0.000018 sec (dot product method) -tri+prep time: 0.000054 sec (incl time to compute L and U) -compute C time: 0.000014 sec -reduce (C) time: 0.000004 sec -rate 5.30 million edges/sec (incl time for U=triu(A)) -rate 16.09 million edges/sec (just tricount itself) -L*U' time (dot): 0.000012 sec (nthreads: 2 speedup 1.16494) +rate 6.89 million edges/sec (incl time for U=triu(A)) +rate 24.07 million edges/sec (just tricount itself) +L*U' time (dot): 0.000012 sec tricount time: 0.000016 sec (dot product method) -tri+prep time: 0.000052 sec (incl time to compute L and U) +tri+prep time: 0.000045 sec (incl time to compute L and U) compute C time: 0.000012 sec reduce (C) time: 0.000004 sec -rate 5.53 million edges/sec (incl time for U=triu(A)) -rate 18.47 million edges/sec (just tricount itself) -L*U' time (dot): 0.000010 sec (nthreads: 4 speedup 1.32671) +rate 6.31 million edges/sec (incl time for U=triu(A)) +rate 18.20 million edges/sec (just tricount itself) +L*U' time (dot): 0.000011 sec (nthreads: 2 speedup 1.12003) tricount time: 0.000014 sec (dot product method) -tri+prep time: 0.000050 sec (incl time to compute L and U) -compute C time: 0.000010 sec +tri+prep time: 0.000044 sec (incl time to compute L and U) +compute C time: 0.000011 sec reduce (C) time: 0.000003 sec -rate 5.73 million edges/sec (incl time for U=triu(A)) -rate 20.90 million edges/sec (just tricount itself) -L*U' time (dot): 0.000010 sec (nthreads: 8 speedup 1.42599) +rate 6.59 million edges/sec (incl time for U=triu(A)) +rate 20.81 million edges/sec (just tricount itself) +L*U' time (dot): 0.000010 sec (nthreads: 4 speedup 1.22214) tricount time: 0.000012 sec (dot product method) -tri+prep time: 0.000049 sec (incl time to compute L and U) +tri+prep time: 0.000042 sec (incl time to compute L and U) compute C time: 0.000010 sec reduce (C) time: 0.000003 sec -rate 5.89 million edges/sec (incl time for U=triu(A)) -rate 23.17 million edges/sec (just tricount itself) +rate 6.81 million edges/sec (incl time for U=triu(A)) +rate 23.09 million edges/sec (just tricount itself) +L*U' time (dot): 0.000009 sec (nthreads: 8 speedup 1.3117) +tricount time: 0.000011 sec (dot product method) +tri+prep time: 0.000041 sec (incl time to compute L and U) +compute C time: 0.000009 sec +reduce (C) time: 0.000002 sec +rate 6.97 million edges/sec (incl time for U=triu(A)) +rate 25.02 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.000033 sec -tricount time: 0.000033 sec (saxpy method) -tri+prep time: 0.000040 sec (incl time to compute L) -compute C time: 0.000033 sec +triangles, method 3: 120 +C=L*L time (saxpy): 0.000028 sec +tricount time: 0.000029 sec (saxpy method) +tri+prep time: 0.000035 sec (incl time to compute L) +compute C time: 0.000028 sec reduce (C) time: 0.000001 sec -rate 7.13 million edges/sec (incl time for L=tril(A)) -rate 8.64 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000015 sec (nthreads: 2 speedup 2.19723) -tricount time: 0.000015 sec (saxpy method) -tri+prep time: 0.000022 sec (incl time to compute L) -compute C time: 0.000015 sec +rate 8.17 million edges/sec (incl time for L=tril(A)) +rate 10.03 million edges/sec (just tricount itself) +triangles, method 3: 120 +C=L*L time (saxpy): 0.000016 sec (nthreads: 2 speedup 1.73448) +tricount time: 0.000017 sec (saxpy method) +tri+prep time: 0.000023 sec (incl time to compute L) +compute C time: 0.000016 sec reduce (C) time: 0.000001 sec -rate 12.81 million edges/sec (incl time for L=tril(A)) -rate 18.67 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000012 sec (nthreads: 4 speedup 2.71136) -tricount time: 0.000013 sec (saxpy method) +rate 12.39 million edges/sec (incl time for L=tril(A)) +rate 17.24 million edges/sec (just tricount itself) +triangles, method 3: 120 +C=L*L time (saxpy): 0.000013 sec (nthreads: 4 speedup 2.10791) +tricount time: 0.000014 sec (saxpy method) tri+prep time: 0.000020 sec (incl time to compute L) -compute C time: 0.000012 sec -reduce (C) time: 0.000000 sec -rate 14.69 million edges/sec (incl time for L=tril(A)) -rate 22.95 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.000012 sec (nthreads: 8 speedup 2.68857) +compute C time: 0.000013 sec +reduce (C) time: 0.000001 sec +rate 14.15 million edges/sec (incl time for L=tril(A)) +rate 20.84 million edges/sec (just tricount itself) +triangles, method 3: 120 +C=L*L time (saxpy): 0.000012 sec (nthreads: 8 speedup 2.27045) tricount time: 0.000013 sec (saxpy method) -tri+prep time: 0.000020 sec (incl time to compute L) +tri+prep time: 0.000019 sec (incl time to compute L) compute C time: 0.000012 sec reduce (C) time: 0.000001 sec -rate 14.56 million edges/sec (incl time for L=tril(A)) -rate 22.62 million edges/sec (just tricount itself) +rate 14.77 million edges/sec (incl time for L=tril(A)) +rate 22.23 million edges/sec (just tricount itself) -------------------------------------------------------------- -Wathen: nx 200 ny 200 n 120801 nz 1762400 method 0, time: 0.133 sec +Wathen: nx 200 ny 200 n 120801 nz 1762400 method 0, time: 0.126 sec -total time to read A matrix: 0.135067 sec +total time to read A matrix: 0.127766 sec n 120801 # edges 881200 -U=triu(A) time: 0.002560 sec -L=tril(A) time: 0.002522 sec +U=triu(A) time: 0.002563 sec +L=tril(A) time: 0.002483 sec ------------------------------------- dot product method: # triangles 2160400 -L*U' time (dot): 0.034713 sec -tricount time: 0.038972 sec (dot product method) -tri+prep time: 0.044054 sec (incl time to compute L and U) -compute C time: 0.034713 sec -reduce (C) time: 0.004259 sec -rate 20.00 million edges/sec (incl time for U=triu(A)) -rate 22.61 million edges/sec (just tricount itself) -L*U' time (dot): 0.022245 sec (nthreads: 2 speedup 1.56046) -tricount time: 0.026859 sec (dot product method) -tri+prep time: 0.031941 sec (incl time to compute L and U) -compute C time: 0.022245 sec -reduce (C) time: 0.004614 sec -rate 27.59 million edges/sec (incl time for U=triu(A)) -rate 32.81 million edges/sec (just tricount itself) -L*U' time (dot): 0.006826 sec (nthreads: 4 speedup 5.08539) -tricount time: 0.008731 sec (dot product method) -tri+prep time: 0.013813 sec (incl time to compute L and U) -compute C time: 0.006826 sec -reduce (C) time: 0.001905 sec -rate 63.79 million edges/sec (incl time for U=triu(A)) -rate 100.93 million edges/sec (just tricount itself) -L*U' time (dot): 0.008368 sec (nthreads: 8 speedup 4.14848) -tricount time: 0.010726 sec (dot product method) -tri+prep time: 0.015808 sec (incl time to compute L and U) -compute C time: 0.008368 sec -reduce (C) time: 0.002358 sec +L*U' time (dot): 0.031311 sec +tricount time: 0.037246 sec (dot product method) +tri+prep time: 0.042292 sec (incl time to compute L and U) +compute C time: 0.031311 sec +reduce (C) time: 0.005935 sec +rate 20.84 million edges/sec (incl time for U=triu(A)) +rate 23.66 million edges/sec (just tricount itself) +L*U' time (dot): 0.011505 sec (nthreads: 2 speedup 2.72157) +tricount time: 0.014218 sec (dot product method) +tri+prep time: 0.019264 sec (incl time to compute L and U) +compute C time: 0.011505 sec +reduce (C) time: 0.002713 sec +rate 45.74 million edges/sec (incl time for U=triu(A)) +rate 61.98 million edges/sec (just tricount itself) +L*U' time (dot): 0.007691 sec (nthreads: 4 speedup 4.07101) +tricount time: 0.010764 sec (dot product method) +tri+prep time: 0.015810 sec (incl time to compute L and U) +compute C time: 0.007691 sec +reduce (C) time: 0.003073 sec rate 55.74 million edges/sec (incl time for U=triu(A)) -rate 82.16 million edges/sec (just tricount itself) -L*U' time (dot): 0.026884 sec -tricount time: 0.031204 sec (dot product method) -tri+prep time: 0.036286 sec (incl time to compute L and U) -compute C time: 0.026884 sec -reduce (C) time: 0.004320 sec -rate 24.28 million edges/sec (incl time for U=triu(A)) -rate 28.24 million edges/sec (just tricount itself) -L*U' time (dot): 0.013448 sec (nthreads: 2 speedup 1.99905) -tricount time: 0.016759 sec (dot product method) -tri+prep time: 0.021841 sec (incl time to compute L and U) -compute C time: 0.013448 sec -reduce (C) time: 0.003310 sec -rate 40.35 million edges/sec (incl time for U=triu(A)) -rate 52.58 million edges/sec (just tricount itself) -L*U' time (dot): 0.007162 sec (nthreads: 4 speedup 3.75373) -tricount time: 0.009101 sec (dot product method) -tri+prep time: 0.014183 sec (incl time to compute L and U) -compute C time: 0.007162 sec -reduce (C) time: 0.001939 sec -rate 62.13 million edges/sec (incl time for U=triu(A)) -rate 96.83 million edges/sec (just tricount itself) -L*U' time (dot): 0.008760 sec (nthreads: 8 speedup 3.069) -tricount time: 0.011839 sec (dot product method) -tri+prep time: 0.016921 sec (incl time to compute L and U) -compute C time: 0.008760 sec -reduce (C) time: 0.003079 sec -rate 52.08 million edges/sec (incl time for U=triu(A)) -rate 74.43 million edges/sec (just tricount itself) +rate 81.87 million edges/sec (just tricount itself) +L*U' time (dot): 0.009845 sec (nthreads: 8 speedup 3.18048) +tricount time: 0.011741 sec (dot product method) +tri+prep time: 0.016787 sec (incl time to compute L and U) +compute C time: 0.009845 sec +reduce (C) time: 0.001896 sec +rate 52.49 million edges/sec (incl time for U=triu(A)) +rate 75.05 million edges/sec (just tricount itself) +L*U' time (dot): 0.023385 sec +tricount time: 0.027309 sec (dot product method) +tri+prep time: 0.032355 sec (incl time to compute L and U) +compute C time: 0.023385 sec +reduce (C) time: 0.003925 sec +rate 27.24 million edges/sec (incl time for U=triu(A)) +rate 32.27 million edges/sec (just tricount itself) +L*U' time (dot): 0.010843 sec (nthreads: 2 speedup 2.1567) +tricount time: 0.013844 sec (dot product method) +tri+prep time: 0.018890 sec (incl time to compute L and U) +compute C time: 0.010843 sec +reduce (C) time: 0.003001 sec +rate 46.65 million edges/sec (incl time for U=triu(A)) +rate 63.65 million edges/sec (just tricount itself) +L*U' time (dot): 0.007708 sec (nthreads: 4 speedup 3.03387) +tricount time: 0.011627 sec (dot product method) +tri+prep time: 0.016673 sec (incl time to compute L and U) +compute C time: 0.007708 sec +reduce (C) time: 0.003919 sec +rate 52.85 million edges/sec (incl time for U=triu(A)) +rate 75.79 million edges/sec (just tricount itself) +L*U' time (dot): 0.006164 sec (nthreads: 8 speedup 3.79354) +tricount time: 0.008035 sec (dot product method) +tri+prep time: 0.013081 sec (incl time to compute L and U) +compute C time: 0.006164 sec +reduce (C) time: 0.001871 sec +rate 67.36 million edges/sec (incl time for U=triu(A)) +rate 109.67 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.023525 sec -tricount time: 0.025656 sec (saxpy method) -tri+prep time: 0.028178 sec (incl time to compute L) -compute C time: 0.023525 sec -reduce (C) time: 0.002131 sec -rate 31.27 million edges/sec (incl time for L=tril(A)) -rate 34.35 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.011029 sec (nthreads: 2 speedup 2.13306) -tricount time: 0.011980 sec (saxpy method) -tri+prep time: 0.014502 sec (incl time to compute L) -compute C time: 0.011029 sec -reduce (C) time: 0.000951 sec -rate 60.76 million edges/sec (incl time for L=tril(A)) -rate 73.56 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.005803 sec (nthreads: 4 speedup 4.05405) -tricount time: 0.006265 sec (saxpy method) -tri+prep time: 0.008787 sec (incl time to compute L) -compute C time: 0.005803 sec -reduce (C) time: 0.000462 sec -rate 100.28 million edges/sec (incl time for L=tril(A)) -rate 140.65 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.006089 sec (nthreads: 8 speedup 3.86381) -tricount time: 0.006851 sec (saxpy method) -tri+prep time: 0.009374 sec (incl time to compute L) -compute C time: 0.006089 sec -reduce (C) time: 0.000763 sec -rate 94.01 million edges/sec (incl time for L=tril(A)) -rate 128.62 million edges/sec (just tricount itself) +triangles, method 3: 2160400 +C=L*L time (saxpy): 0.028242 sec +tricount time: 0.030344 sec (saxpy method) +tri+prep time: 0.032826 sec (incl time to compute L) +compute C time: 0.028242 sec +reduce (C) time: 0.002101 sec +rate 26.84 million edges/sec (incl time for L=tril(A)) +rate 29.04 million edges/sec (just tricount itself) +triangles, method 3: 2160400 +C=L*L time (saxpy): 0.024173 sec (nthreads: 2 speedup 1.16837) +tricount time: 0.025586 sec (saxpy method) +tri+prep time: 0.028068 sec (incl time to compute L) +compute C time: 0.024173 sec +reduce (C) time: 0.001413 sec +rate 31.39 million edges/sec (incl time for L=tril(A)) +rate 34.44 million edges/sec (just tricount itself) +triangles, method 3: 2160400 +C=L*L time (saxpy): 0.012087 sec (nthreads: 4 speedup 2.33654) +tricount time: 0.012740 sec (saxpy method) +tri+prep time: 0.015223 sec (incl time to compute L) +compute C time: 0.012087 sec +reduce (C) time: 0.000653 sec +rate 57.89 million edges/sec (incl time for L=tril(A)) +rate 69.17 million edges/sec (just tricount itself) +triangles, method 3: 2160400 +C=L*L time (saxpy): 0.008452 sec (nthreads: 8 speedup 3.34138) +tricount time: 0.008817 sec (saxpy method) +tri+prep time: 0.011300 sec (incl time to compute L) +compute C time: 0.008452 sec +reduce (C) time: 0.000365 sec +rate 77.99 million edges/sec (incl time for L=tril(A)) +rate 99.94 million edges/sec (just tricount itself) -------------------------------------------------------------- random 10000 by 10000, nz: 199768, method 0 time 0.023 sec -total time to read A matrix: 0.023445 sec +total time to read A matrix: 0.023617 sec n 10000 # edges 99884 -U=triu(A) time: 0.000208 sec -L=tril(A) time: 0.000138 sec +U=triu(A) time: 0.000328 sec +L=tril(A) time: 0.000219 sec ------------------------------------- dot product method: # triangles 1357 -L*U' time (dot): 0.010097 sec -tricount time: 0.010654 sec (dot product method) -tri+prep time: 0.011000 sec (incl time to compute L and U) -compute C time: 0.010097 sec -reduce (C) time: 0.000557 sec -rate 9.08 million edges/sec (incl time for U=triu(A)) -rate 9.38 million edges/sec (just tricount itself) -L*U' time (dot): 0.005951 sec (nthreads: 2 speedup 1.69652) -tricount time: 0.006160 sec (dot product method) -tri+prep time: 0.006506 sec (incl time to compute L and U) -compute C time: 0.005951 sec -reduce (C) time: 0.000209 sec -rate 15.35 million edges/sec (incl time for U=triu(A)) -rate 16.22 million edges/sec (just tricount itself) -L*U' time (dot): 0.003291 sec (nthreads: 4 speedup 3.06807) -tricount time: 0.003470 sec (dot product method) -tri+prep time: 0.003816 sec (incl time to compute L and U) -compute C time: 0.003291 sec -reduce (C) time: 0.000179 sec -rate 26.17 million edges/sec (incl time for U=triu(A)) -rate 28.78 million edges/sec (just tricount itself) -L*U' time (dot): 0.005730 sec (nthreads: 8 speedup 1.76216) -tricount time: 0.005924 sec (dot product method) -tri+prep time: 0.006270 sec (incl time to compute L and U) -compute C time: 0.005730 sec -reduce (C) time: 0.000195 sec -rate 15.93 million edges/sec (incl time for U=triu(A)) -rate 16.86 million edges/sec (just tricount itself) -L*U' time (dot): 0.009789 sec -tricount time: 0.010226 sec (dot product method) -tri+prep time: 0.010572 sec (incl time to compute L and U) -compute C time: 0.009789 sec -reduce (C) time: 0.000436 sec -rate 9.45 million edges/sec (incl time for U=triu(A)) -rate 9.77 million edges/sec (just tricount itself) -L*U' time (dot): 0.005670 sec (nthreads: 2 speedup 1.72665) -tricount time: 0.005965 sec (dot product method) -tri+prep time: 0.006311 sec (incl time to compute L and U) -compute C time: 0.005670 sec -reduce (C) time: 0.000295 sec -rate 15.83 million edges/sec (incl time for U=triu(A)) -rate 16.74 million edges/sec (just tricount itself) -L*U' time (dot): 0.003481 sec (nthreads: 4 speedup 2.81227) -tricount time: 0.003752 sec (dot product method) -tri+prep time: 0.004098 sec (incl time to compute L and U) -compute C time: 0.003481 sec -reduce (C) time: 0.000271 sec -rate 24.37 million edges/sec (incl time for U=triu(A)) -rate 26.62 million edges/sec (just tricount itself) -L*U' time (dot): 0.003737 sec (nthreads: 8 speedup 2.61945) -tricount time: 0.003946 sec (dot product method) -tri+prep time: 0.004292 sec (incl time to compute L and U) -compute C time: 0.003737 sec -reduce (C) time: 0.000209 sec -rate 23.27 million edges/sec (incl time for U=triu(A)) -rate 25.31 million edges/sec (just tricount itself) +L*U' time (dot): 0.008270 sec +tricount time: 0.008607 sec (dot product method) +tri+prep time: 0.009154 sec (incl time to compute L and U) +compute C time: 0.008270 sec +reduce (C) time: 0.000337 sec +rate 10.91 million edges/sec (incl time for U=triu(A)) +rate 11.60 million edges/sec (just tricount itself) +L*U' time (dot): 0.004090 sec (nthreads: 2 speedup 2.02205) +tricount time: 0.004246 sec (dot product method) +tri+prep time: 0.004793 sec (incl time to compute L and U) +compute C time: 0.004090 sec +reduce (C) time: 0.000156 sec +rate 20.84 million edges/sec (incl time for U=triu(A)) +rate 23.53 million edges/sec (just tricount itself) +L*U' time (dot): 0.002451 sec (nthreads: 4 speedup 3.37446) +tricount time: 0.002603 sec (dot product method) +tri+prep time: 0.003150 sec (incl time to compute L and U) +compute C time: 0.002451 sec +reduce (C) time: 0.000153 sec +rate 31.71 million edges/sec (incl time for U=triu(A)) +rate 38.37 million edges/sec (just tricount itself) +L*U' time (dot): 0.002521 sec (nthreads: 8 speedup 3.28008) +tricount time: 0.002687 sec (dot product method) +tri+prep time: 0.003234 sec (incl time to compute L and U) +compute C time: 0.002521 sec +reduce (C) time: 0.000165 sec +rate 30.89 million edges/sec (incl time for U=triu(A)) +rate 37.18 million edges/sec (just tricount itself) +L*U' time (dot): 0.007348 sec +tricount time: 0.007734 sec (dot product method) +tri+prep time: 0.008280 sec (incl time to compute L and U) +compute C time: 0.007348 sec +reduce (C) time: 0.000386 sec +rate 12.06 million edges/sec (incl time for U=triu(A)) +rate 12.92 million edges/sec (just tricount itself) +L*U' time (dot): 0.004463 sec (nthreads: 2 speedup 1.64641) +tricount time: 0.004677 sec (dot product method) +tri+prep time: 0.005224 sec (incl time to compute L and U) +compute C time: 0.004463 sec +reduce (C) time: 0.000214 sec +rate 19.12 million edges/sec (incl time for U=triu(A)) +rate 21.36 million edges/sec (just tricount itself) +L*U' time (dot): 0.002655 sec (nthreads: 4 speedup 2.76719) +tricount time: 0.002886 sec (dot product method) +tri+prep time: 0.003433 sec (incl time to compute L and U) +compute C time: 0.002655 sec +reduce (C) time: 0.000231 sec +rate 29.09 million edges/sec (incl time for U=triu(A)) +rate 34.60 million edges/sec (just tricount itself) +L*U' time (dot): 0.004552 sec (nthreads: 8 speedup 1.61416) +tricount time: 0.004864 sec (dot product method) +tri+prep time: 0.005411 sec (incl time to compute L and U) +compute C time: 0.004552 sec +reduce (C) time: 0.000311 sec +rate 18.46 million edges/sec (incl time for U=triu(A)) +rate 20.54 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.003094 sec -tricount time: 0.003098 sec (saxpy method) -tri+prep time: 0.003237 sec (incl time to compute L) -compute C time: 0.003094 sec -reduce (C) time: 0.000004 sec -rate 30.86 million edges/sec (incl time for L=tril(A)) -rate 32.24 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.001952 sec (nthreads: 2 speedup 1.58528) -tricount time: 0.001956 sec (saxpy method) -tri+prep time: 0.002094 sec (incl time to compute L) -compute C time: 0.001952 sec +triangles, method 3: 1357 +C=L*L time (saxpy): 0.003086 sec +tricount time: 0.003091 sec (saxpy method) +tri+prep time: 0.003310 sec (incl time to compute L) +compute C time: 0.003086 sec +reduce (C) time: 0.000005 sec +rate 30.17 million edges/sec (incl time for L=tril(A)) +rate 32.31 million edges/sec (just tricount itself) +triangles, method 3: 1357 +C=L*L time (saxpy): 0.001912 sec (nthreads: 2 speedup 1.61403) +tricount time: 0.001916 sec (saxpy method) +tri+prep time: 0.002136 sec (incl time to compute L) +compute C time: 0.001912 sec reduce (C) time: 0.000004 sec -rate 47.70 million edges/sec (incl time for L=tril(A)) -rate 51.07 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.001451 sec (nthreads: 4 speedup 2.13166) -tricount time: 0.001456 sec (saxpy method) -tri+prep time: 0.001594 sec (incl time to compute L) -compute C time: 0.001451 sec +rate 46.77 million edges/sec (incl time for L=tril(A)) +rate 52.12 million edges/sec (just tricount itself) +triangles, method 3: 1357 +C=L*L time (saxpy): 0.001379 sec (nthreads: 4 speedup 2.23754) +tricount time: 0.001383 sec (saxpy method) +tri+prep time: 0.001603 sec (incl time to compute L) +compute C time: 0.001379 sec reduce (C) time: 0.000004 sec -rate 62.65 million edges/sec (incl time for L=tril(A)) -rate 68.60 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.001367 sec (nthreads: 8 speedup 2.26374) -tricount time: 0.001373 sec (saxpy method) -tri+prep time: 0.001511 sec (incl time to compute L) -compute C time: 0.001367 sec -reduce (C) time: 0.000006 sec -rate 66.09 million edges/sec (incl time for L=tril(A)) -rate 72.75 million edges/sec (just tricount itself) +rate 62.32 million edges/sec (incl time for L=tril(A)) +rate 72.20 million edges/sec (just tricount itself) +triangles, method 3: 1357 +C=L*L time (saxpy): 0.001191 sec (nthreads: 8 speedup 2.59029) +tricount time: 0.001196 sec (saxpy method) +tri+prep time: 0.001416 sec (incl time to compute L) +compute C time: 0.001191 sec +reduce (C) time: 0.000005 sec +rate 70.56 million edges/sec (incl time for L=tril(A)) +rate 83.49 million edges/sec (just tricount itself) -------------------------------------------------------------- -random 10000 by 10000, nz: 199768, method 1 time 0.020 sec +random 10000 by 10000, nz: 199768, method 1 time 0.018 sec -total time to read A matrix: 0.020932 sec +total time to read A matrix: 0.019086 sec n 10000 # edges 99884 -U=triu(A) time: 0.000217 sec -L=tril(A) time: 0.000126 sec +U=triu(A) time: 0.000581 sec +L=tril(A) time: 0.000302 sec ------------------------------------- dot product method: # triangles 1357 -L*U' time (dot): 0.010906 sec -tricount time: 0.011256 sec (dot product method) -tri+prep time: 0.011598 sec (incl time to compute L and U) -compute C time: 0.010906 sec -reduce (C) time: 0.000350 sec -rate 8.61 million edges/sec (incl time for U=triu(A)) -rate 8.87 million edges/sec (just tricount itself) -L*U' time (dot): 0.006398 sec (nthreads: 2 speedup 1.70455) -tricount time: 0.006774 sec (dot product method) -tri+prep time: 0.007116 sec (incl time to compute L and U) -compute C time: 0.006398 sec -reduce (C) time: 0.000376 sec -rate 14.04 million edges/sec (incl time for U=triu(A)) -rate 14.75 million edges/sec (just tricount itself) -L*U' time (dot): 0.004006 sec (nthreads: 4 speedup 2.72215) -tricount time: 0.004308 sec (dot product method) -tri+prep time: 0.004651 sec (incl time to compute L and U) -compute C time: 0.004006 sec -reduce (C) time: 0.000302 sec -rate 21.48 million edges/sec (incl time for U=triu(A)) -rate 23.19 million edges/sec (just tricount itself) -L*U' time (dot): 0.006057 sec (nthreads: 8 speedup 1.80051) -tricount time: 0.006477 sec (dot product method) -tri+prep time: 0.006820 sec (incl time to compute L and U) -compute C time: 0.006057 sec +L*U' time (dot): 0.008025 sec +tricount time: 0.008343 sec (dot product method) +tri+prep time: 0.009226 sec (incl time to compute L and U) +compute C time: 0.008025 sec +reduce (C) time: 0.000319 sec +rate 10.83 million edges/sec (incl time for U=triu(A)) +rate 11.97 million edges/sec (just tricount itself) +L*U' time (dot): 0.004084 sec (nthreads: 2 speedup 1.96498) +tricount time: 0.004253 sec (dot product method) +tri+prep time: 0.005136 sec (incl time to compute L and U) +compute C time: 0.004084 sec +reduce (C) time: 0.000169 sec +rate 19.45 million edges/sec (incl time for U=triu(A)) +rate 23.48 million edges/sec (just tricount itself) +L*U' time (dot): 0.002465 sec (nthreads: 4 speedup 3.25503) +tricount time: 0.002619 sec (dot product method) +tri+prep time: 0.003501 sec (incl time to compute L and U) +compute C time: 0.002465 sec +reduce (C) time: 0.000154 sec +rate 28.53 million edges/sec (incl time for U=triu(A)) +rate 38.14 million edges/sec (just tricount itself) +L*U' time (dot): 0.002651 sec (nthreads: 8 speedup 3.02704) +tricount time: 0.003370 sec (dot product method) +tri+prep time: 0.004252 sec (incl time to compute L and U) +compute C time: 0.002651 sec +reduce (C) time: 0.000719 sec +rate 23.49 million edges/sec (incl time for U=triu(A)) +rate 29.64 million edges/sec (just tricount itself) +L*U' time (dot): 0.007855 sec +tricount time: 0.008275 sec (dot product method) +tri+prep time: 0.009157 sec (incl time to compute L and U) +compute C time: 0.007855 sec reduce (C) time: 0.000420 sec -rate 14.65 million edges/sec (incl time for U=triu(A)) -rate 15.42 million edges/sec (just tricount itself) -L*U' time (dot): 0.011083 sec -tricount time: 0.011476 sec (dot product method) -tri+prep time: 0.011819 sec (incl time to compute L and U) -compute C time: 0.011083 sec -reduce (C) time: 0.000393 sec -rate 8.45 million edges/sec (incl time for U=triu(A)) -rate 8.70 million edges/sec (just tricount itself) -L*U' time (dot): 0.006107 sec (nthreads: 2 speedup 1.81493) -tricount time: 0.006325 sec (dot product method) -tri+prep time: 0.006668 sec (incl time to compute L and U) -compute C time: 0.006107 sec -reduce (C) time: 0.000219 sec -rate 14.98 million edges/sec (incl time for U=triu(A)) -rate 15.79 million edges/sec (just tricount itself) -L*U' time (dot): 0.003795 sec (nthreads: 4 speedup 2.92064) -tricount time: 0.004084 sec (dot product method) -tri+prep time: 0.004426 sec (incl time to compute L and U) -compute C time: 0.003795 sec -reduce (C) time: 0.000289 sec -rate 22.57 million edges/sec (incl time for U=triu(A)) -rate 24.46 million edges/sec (just tricount itself) -L*U' time (dot): 0.005885 sec (nthreads: 8 speedup 1.88311) -tricount time: 0.006190 sec (dot product method) -tri+prep time: 0.006532 sec (incl time to compute L and U) -compute C time: 0.005885 sec -reduce (C) time: 0.000304 sec -rate 15.29 million edges/sec (incl time for U=triu(A)) -rate 16.14 million edges/sec (just tricount itself) +rate 10.91 million edges/sec (incl time for U=triu(A)) +rate 12.07 million edges/sec (just tricount itself) +L*U' time (dot): 0.004511 sec (nthreads: 2 speedup 1.7412) +tricount time: 0.004818 sec (dot product method) +tri+prep time: 0.005701 sec (incl time to compute L and U) +compute C time: 0.004511 sec +reduce (C) time: 0.000307 sec +rate 17.52 million edges/sec (incl time for U=triu(A)) +rate 20.73 million edges/sec (just tricount itself) +L*U' time (dot): 0.002717 sec (nthreads: 4 speedup 2.89116) +tricount time: 0.002905 sec (dot product method) +tri+prep time: 0.003787 sec (incl time to compute L and U) +compute C time: 0.002717 sec +reduce (C) time: 0.000188 sec +rate 26.37 million edges/sec (incl time for U=triu(A)) +rate 34.39 million edges/sec (just tricount itself) +L*U' time (dot): 0.002350 sec (nthreads: 8 speedup 3.34247) +tricount time: 0.002517 sec (dot product method) +tri+prep time: 0.003400 sec (incl time to compute L and U) +compute C time: 0.002350 sec +reduce (C) time: 0.000167 sec +rate 29.38 million edges/sec (incl time for U=triu(A)) +rate 39.68 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 0.003407 sec -tricount time: 0.003411 sec (saxpy method) -tri+prep time: 0.003537 sec (incl time to compute L) -compute C time: 0.003407 sec +triangles, method 3: 1357 +C=L*L time (saxpy): 0.002995 sec +tricount time: 0.002999 sec (saxpy method) +tri+prep time: 0.003301 sec (incl time to compute L) +compute C time: 0.002995 sec +reduce (C) time: 0.000004 sec +rate 30.26 million edges/sec (incl time for L=tril(A)) +rate 33.31 million edges/sec (just tricount itself) +triangles, method 3: 1357 +C=L*L time (saxpy): 0.001938 sec (nthreads: 2 speedup 1.54549) +tricount time: 0.001942 sec (saxpy method) +tri+prep time: 0.002244 sec (incl time to compute L) +compute C time: 0.001938 sec reduce (C) time: 0.000005 sec -rate 28.24 million edges/sec (incl time for L=tril(A)) -rate 29.28 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.002249 sec (nthreads: 2 speedup 1.51486) -tricount time: 0.002254 sec (saxpy method) -tri+prep time: 0.002380 sec (incl time to compute L) -compute C time: 0.002249 sec +rate 44.51 million edges/sec (incl time for L=tril(A)) +rate 51.43 million edges/sec (just tricount itself) +triangles, method 3: 1357 +C=L*L time (saxpy): 0.001348 sec (nthreads: 4 speedup 2.22153) +tricount time: 0.001352 sec (saxpy method) +tri+prep time: 0.001654 sec (incl time to compute L) +compute C time: 0.001348 sec +reduce (C) time: 0.000004 sec +rate 60.40 million edges/sec (incl time for L=tril(A)) +rate 73.86 million edges/sec (just tricount itself) +triangles, method 3: 1357 +C=L*L time (saxpy): 0.001254 sec (nthreads: 8 speedup 2.38776) +tricount time: 0.001259 sec (saxpy method) +tri+prep time: 0.001561 sec (incl time to compute L) +compute C time: 0.001254 sec reduce (C) time: 0.000005 sec -rate 41.98 million edges/sec (incl time for L=tril(A)) -rate 44.32 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.001689 sec (nthreads: 4 speedup 2.01672) -tricount time: 0.001697 sec (saxpy method) -tri+prep time: 0.001822 sec (incl time to compute L) -compute C time: 0.001689 sec -reduce (C) time: 0.000007 sec -rate 54.81 million edges/sec (incl time for L=tril(A)) -rate 58.87 million edges/sec (just tricount itself) -C=L*L time (saxpy): 0.001550 sec (nthreads: 8 speedup 2.19831) -tricount time: 0.001558 sec (saxpy method) -tri+prep time: 0.001684 sec (incl time to compute L) -compute C time: 0.001550 sec -reduce (C) time: 0.000008 sec -rate 59.32 million edges/sec (incl time for L=tril(A)) -rate 64.11 million edges/sec (just tricount itself) +rate 63.99 million edges/sec (incl time for L=tril(A)) +rate 79.32 million edges/sec (just tricount itself) -------------------------------------------------------------- -random 100000 by 100000, nz: 19980330, method 0 time 2.288 sec +random 100000 by 100000, nz: 19980330, method 0 time 2.296 sec -total time to read A matrix: 2.312987 sec +total time to read A matrix: 2.325069 sec n 100000 # edges 9990165 -U=triu(A) time: 0.018055 sec -L=tril(A) time: 0.019905 sec +U=triu(A) time: 0.017604 sec +L=tril(A) time: 0.019649 sec ------------------------------------- dot product method: # triangles 1330131 -L*U' time (dot): 10.406264 sec -tricount time: 10.444652 sec (dot product method) -tri+prep time: 10.482612 sec (incl time to compute L and U) -compute C time: 10.406264 sec -reduce (C) time: 0.038388 sec -rate 0.95 million edges/sec (incl time for U=triu(A)) -rate 0.96 million edges/sec (just tricount itself) -L*U' time (dot): 5.500298 sec (nthreads: 2 speedup 1.89195) -tricount time: 5.522717 sec (dot product method) -tri+prep time: 5.560678 sec (incl time to compute L and U) -compute C time: 5.500298 sec -reduce (C) time: 0.022419 sec -rate 1.80 million edges/sec (incl time for U=triu(A)) -rate 1.81 million edges/sec (just tricount itself) -L*U' time (dot): 3.877952 sec (nthreads: 4 speedup 2.68344) -tricount time: 3.897149 sec (dot product method) -tri+prep time: 3.935109 sec (incl time to compute L and U) -compute C time: 3.877952 sec -reduce (C) time: 0.019197 sec -rate 2.54 million edges/sec (incl time for U=triu(A)) -rate 2.56 million edges/sec (just tricount itself) -L*U' time (dot): 2.696096 sec (nthreads: 8 speedup 3.85975) -tricount time: 2.716718 sec (dot product method) -tri+prep time: 2.754678 sec (incl time to compute L and U) -compute C time: 2.696096 sec -reduce (C) time: 0.020622 sec -rate 3.63 million edges/sec (incl time for U=triu(A)) -rate 3.68 million edges/sec (just tricount itself) -L*U' time (dot): 11.380700 sec -tricount time: 11.415574 sec (dot product method) -tri+prep time: 11.453534 sec (incl time to compute L and U) -compute C time: 11.380700 sec -reduce (C) time: 0.034874 sec -rate 0.87 million edges/sec (incl time for U=triu(A)) -rate 0.88 million edges/sec (just tricount itself) -L*U' time (dot): 6.448143 sec (nthreads: 2 speedup 1.76496) -tricount time: 6.472799 sec (dot product method) -tri+prep time: 6.510759 sec (incl time to compute L and U) -compute C time: 6.448143 sec -reduce (C) time: 0.024655 sec -rate 1.53 million edges/sec (incl time for U=triu(A)) -rate 1.54 million edges/sec (just tricount itself) -L*U' time (dot): 3.976479 sec (nthreads: 4 speedup 2.862) -tricount time: 3.995512 sec (dot product method) -tri+prep time: 4.033473 sec (incl time to compute L and U) -compute C time: 3.976479 sec -reduce (C) time: 0.019033 sec -rate 2.48 million edges/sec (incl time for U=triu(A)) -rate 2.50 million edges/sec (just tricount itself) -L*U' time (dot): 2.843621 sec (nthreads: 8 speedup 4.00219) -tricount time: 2.863759 sec (dot product method) -tri+prep time: 2.901720 sec (incl time to compute L and U) -compute C time: 2.843621 sec -reduce (C) time: 0.020138 sec -rate 3.44 million edges/sec (incl time for U=triu(A)) -rate 3.49 million edges/sec (just tricount itself) +L*U' time (dot): 7.128369 sec +tricount time: 7.163533 sec (dot product method) +tri+prep time: 7.200786 sec (incl time to compute L and U) +compute C time: 7.128369 sec +reduce (C) time: 0.035164 sec +rate 1.39 million edges/sec (incl time for U=triu(A)) +rate 1.39 million edges/sec (just tricount itself) +L*U' time (dot): 3.510440 sec (nthreads: 2 speedup 2.03062) +tricount time: 3.532405 sec (dot product method) +tri+prep time: 3.569658 sec (incl time to compute L and U) +compute C time: 3.510440 sec +reduce (C) time: 0.021965 sec +rate 2.80 million edges/sec (incl time for U=triu(A)) +rate 2.83 million edges/sec (just tricount itself) +L*U' time (dot): 1.912733 sec (nthreads: 4 speedup 3.7268) +tricount time: 1.929098 sec (dot product method) +tri+prep time: 1.966351 sec (incl time to compute L and U) +compute C time: 1.912733 sec +reduce (C) time: 0.016365 sec +rate 5.08 million edges/sec (incl time for U=triu(A)) +rate 5.18 million edges/sec (just tricount itself) +L*U' time (dot): 1.096600 sec (nthreads: 8 speedup 6.50043) +tricount time: 1.113480 sec (dot product method) +tri+prep time: 1.150733 sec (incl time to compute L and U) +compute C time: 1.096600 sec +reduce (C) time: 0.016880 sec +rate 8.68 million edges/sec (incl time for U=triu(A)) +rate 8.97 million edges/sec (just tricount itself) +L*U' time (dot): 8.085635 sec +tricount time: 8.117637 sec (dot product method) +tri+prep time: 8.154890 sec (incl time to compute L and U) +compute C time: 8.085635 sec +reduce (C) time: 0.032002 sec +rate 1.23 million edges/sec (incl time for U=triu(A)) +rate 1.23 million edges/sec (just tricount itself) +L*U' time (dot): 3.666974 sec (nthreads: 2 speedup 2.20499) +tricount time: 3.686753 sec (dot product method) +tri+prep time: 3.724006 sec (incl time to compute L and U) +compute C time: 3.666974 sec +reduce (C) time: 0.019779 sec +rate 2.68 million edges/sec (incl time for U=triu(A)) +rate 2.71 million edges/sec (just tricount itself) +L*U' time (dot): 2.156598 sec (nthreads: 4 speedup 3.74925) +tricount time: 2.181005 sec (dot product method) +tri+prep time: 2.218258 sec (incl time to compute L and U) +compute C time: 2.156598 sec +reduce (C) time: 0.024407 sec +rate 4.50 million edges/sec (incl time for U=triu(A)) +rate 4.58 million edges/sec (just tricount itself) +L*U' time (dot): 1.662084 sec (nthreads: 8 speedup 4.86476) +tricount time: 1.681525 sec (dot product method) +tri+prep time: 1.718778 sec (incl time to compute L and U) +compute C time: 1.662084 sec +reduce (C) time: 0.019441 sec +rate 5.81 million edges/sec (incl time for U=triu(A)) +rate 5.94 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 5.509919 sec -tricount time: 5.514612 sec (saxpy method) -tri+prep time: 5.534517 sec (incl time to compute L) -compute C time: 5.509919 sec -reduce (C) time: 0.004693 sec -rate 1.81 million edges/sec (incl time for L=tril(A)) -rate 1.81 million edges/sec (just tricount itself) -C=L*L time (saxpy): 3.173495 sec (nthreads: 2 speedup 1.73623) -tricount time: 3.176608 sec (saxpy method) -tri+prep time: 3.196513 sec (incl time to compute L) -compute C time: 3.173495 sec -reduce (C) time: 0.003114 sec -rate 3.13 million edges/sec (incl time for L=tril(A)) -rate 3.14 million edges/sec (just tricount itself) -C=L*L time (saxpy): 1.828458 sec (nthreads: 4 speedup 3.01342) -tricount time: 1.830920 sec (saxpy method) -tri+prep time: 1.850825 sec (incl time to compute L) -compute C time: 1.828458 sec -reduce (C) time: 0.002462 sec -rate 5.40 million edges/sec (incl time for L=tril(A)) -rate 5.46 million edges/sec (just tricount itself) -C=L*L time (saxpy): 2.238881 sec (nthreads: 8 speedup 2.46101) -tricount time: 2.239755 sec (saxpy method) -tri+prep time: 2.259660 sec (incl time to compute L) -compute C time: 2.238881 sec -reduce (C) time: 0.000873 sec -rate 4.42 million edges/sec (incl time for L=tril(A)) -rate 4.46 million edges/sec (just tricount itself) +triangles, method 3: 1330131 +C=L*L time (saxpy): 5.713133 sec +tricount time: 5.717672 sec (saxpy method) +tri+prep time: 5.737321 sec (incl time to compute L) +compute C time: 5.713133 sec +reduce (C) time: 0.004539 sec +rate 1.74 million edges/sec (incl time for L=tril(A)) +rate 1.75 million edges/sec (just tricount itself) +triangles, method 3: 1330131 +C=L*L time (saxpy): 3.236083 sec (nthreads: 2 speedup 1.76545) +tricount time: 3.240762 sec (saxpy method) +tri+prep time: 3.260411 sec (incl time to compute L) +compute C time: 3.236083 sec +reduce (C) time: 0.004679 sec +rate 3.06 million edges/sec (incl time for L=tril(A)) +rate 3.08 million edges/sec (just tricount itself) +triangles, method 3: 1330131 +C=L*L time (saxpy): 2.169659 sec (nthreads: 4 speedup 2.63319) +tricount time: 2.172323 sec (saxpy method) +tri+prep time: 2.191972 sec (incl time to compute L) +compute C time: 2.169659 sec +reduce (C) time: 0.002664 sec +rate 4.56 million edges/sec (incl time for L=tril(A)) +rate 4.60 million edges/sec (just tricount itself) +triangles, method 3: 1330131 +C=L*L time (saxpy): 2.109164 sec (nthreads: 8 speedup 2.70872) +tricount time: 2.110115 sec (saxpy method) +tri+prep time: 2.129765 sec (incl time to compute L) +compute C time: 2.109164 sec +reduce (C) time: 0.000952 sec +rate 4.69 million edges/sec (incl time for L=tril(A)) +rate 4.73 million edges/sec (just tricount itself) -------------------------------------------------------------- -random 100000 by 100000, nz: 19980330, method 1 time 1.729 sec +random 100000 by 100000, nz: 19980330, method 1 time 2.239 sec -total time to read A matrix: 1.752646 sec +total time to read A matrix: 2.273442 sec n 100000 # edges 9990165 -U=triu(A) time: 0.017521 sec -L=tril(A) time: 0.019028 sec +U=triu(A) time: 0.021285 sec +L=tril(A) time: 0.019572 sec ------------------------------------- dot product method: # triangles 1330131 -L*U' time (dot): 10.763829 sec -tricount time: 10.801652 sec (dot product method) -tri+prep time: 10.838201 sec (incl time to compute L and U) -compute C time: 10.763829 sec -reduce (C) time: 0.037823 sec -rate 0.92 million edges/sec (incl time for U=triu(A)) -rate 0.92 million edges/sec (just tricount itself) -L*U' time (dot): 5.594314 sec (nthreads: 2 speedup 1.92407) -tricount time: 5.620549 sec (dot product method) -tri+prep time: 5.657098 sec (incl time to compute L and U) -compute C time: 5.594314 sec -reduce (C) time: 0.026235 sec -rate 1.77 million edges/sec (incl time for U=triu(A)) -rate 1.78 million edges/sec (just tricount itself) -L*U' time (dot): 3.932143 sec (nthreads: 4 speedup 2.7374) -tricount time: 3.951585 sec (dot product method) -tri+prep time: 3.988135 sec (incl time to compute L and U) -compute C time: 3.932143 sec -reduce (C) time: 0.019443 sec -rate 2.50 million edges/sec (incl time for U=triu(A)) -rate 2.53 million edges/sec (just tricount itself) -L*U' time (dot): 2.689850 sec (nthreads: 8 speedup 4.00165) -tricount time: 2.710086 sec (dot product method) -tri+prep time: 2.746635 sec (incl time to compute L and U) -compute C time: 2.689850 sec -reduce (C) time: 0.020236 sec -rate 3.64 million edges/sec (incl time for U=triu(A)) -rate 3.69 million edges/sec (just tricount itself) -L*U' time (dot): 10.959365 sec -tricount time: 10.994169 sec (dot product method) -tri+prep time: 11.030718 sec (incl time to compute L and U) -compute C time: 10.959365 sec -reduce (C) time: 0.034805 sec -rate 0.91 million edges/sec (incl time for U=triu(A)) -rate 0.91 million edges/sec (just tricount itself) -L*U' time (dot): 6.370761 sec (nthreads: 2 speedup 1.72026) -tricount time: 6.394619 sec (dot product method) -tri+prep time: 6.431168 sec (incl time to compute L and U) -compute C time: 6.370761 sec -reduce (C) time: 0.023858 sec -rate 1.55 million edges/sec (incl time for U=triu(A)) -rate 1.56 million edges/sec (just tricount itself) -L*U' time (dot): 3.950553 sec (nthreads: 4 speedup 2.77413) -tricount time: 3.970562 sec (dot product method) -tri+prep time: 4.007111 sec (incl time to compute L and U) -compute C time: 3.950553 sec -reduce (C) time: 0.020008 sec -rate 2.49 million edges/sec (incl time for U=triu(A)) -rate 2.52 million edges/sec (just tricount itself) -L*U' time (dot): 2.815654 sec (nthreads: 8 speedup 3.8923) -tricount time: 2.836292 sec (dot product method) -tri+prep time: 2.872841 sec (incl time to compute L and U) -compute C time: 2.815654 sec -reduce (C) time: 0.020638 sec -rate 3.48 million edges/sec (incl time for U=triu(A)) -rate 3.52 million edges/sec (just tricount itself) +L*U' time (dot): 7.395066 sec +tricount time: 7.429692 sec (dot product method) +tri+prep time: 7.470549 sec (incl time to compute L and U) +compute C time: 7.395066 sec +reduce (C) time: 0.034626 sec +rate 1.34 million edges/sec (incl time for U=triu(A)) +rate 1.34 million edges/sec (just tricount itself) +L*U' time (dot): 3.486968 sec (nthreads: 2 speedup 2.12077) +tricount time: 3.508906 sec (dot product method) +tri+prep time: 3.549763 sec (incl time to compute L and U) +compute C time: 3.486968 sec +reduce (C) time: 0.021938 sec +rate 2.81 million edges/sec (incl time for U=triu(A)) +rate 2.85 million edges/sec (just tricount itself) +L*U' time (dot): 2.862556 sec (nthreads: 4 speedup 2.58338) +tricount time: 2.902115 sec (dot product method) +tri+prep time: 2.942972 sec (incl time to compute L and U) +compute C time: 2.862556 sec +reduce (C) time: 0.039559 sec +rate 3.39 million edges/sec (incl time for U=triu(A)) +rate 3.44 million edges/sec (just tricount itself) +L*U' time (dot): 1.379506 sec (nthreads: 8 speedup 5.36066) +tricount time: 1.406556 sec (dot product method) +tri+prep time: 1.447413 sec (incl time to compute L and U) +compute C time: 1.379506 sec +reduce (C) time: 0.027050 sec +rate 6.90 million edges/sec (incl time for U=triu(A)) +rate 7.10 million edges/sec (just tricount itself) +L*U' time (dot): 13.986013 sec +tricount time: 14.047180 sec (dot product method) +tri+prep time: 14.088037 sec (incl time to compute L and U) +compute C time: 13.986013 sec +reduce (C) time: 0.061167 sec +rate 0.71 million edges/sec (incl time for U=triu(A)) +rate 0.71 million edges/sec (just tricount itself) +L*U' time (dot): 5.212362 sec (nthreads: 2 speedup 2.68324) +tricount time: 5.232665 sec (dot product method) +tri+prep time: 5.273522 sec (incl time to compute L and U) +compute C time: 5.212362 sec +reduce (C) time: 0.020303 sec +rate 1.89 million edges/sec (incl time for U=triu(A)) +rate 1.91 million edges/sec (just tricount itself) +L*U' time (dot): 2.603460 sec (nthreads: 4 speedup 5.37209) +tricount time: 2.621100 sec (dot product method) +tri+prep time: 2.661957 sec (incl time to compute L and U) +compute C time: 2.603460 sec +reduce (C) time: 0.017640 sec +rate 3.75 million edges/sec (incl time for U=triu(A)) +rate 3.81 million edges/sec (just tricount itself) +L*U' time (dot): 1.643353 sec (nthreads: 8 speedup 8.51066) +tricount time: 1.678784 sec (dot product method) +tri+prep time: 1.719641 sec (incl time to compute L and U) +compute C time: 1.643353 sec +reduce (C) time: 0.035431 sec +rate 5.81 million edges/sec (incl time for U=triu(A)) +rate 5.95 million edges/sec (just tricount itself) ----------------------------------- saxpy method: -C=L*L time (saxpy): 5.317642 sec -tricount time: 5.322329 sec (saxpy method) -tri+prep time: 5.341357 sec (incl time to compute L) -compute C time: 5.317642 sec -reduce (C) time: 0.004687 sec -rate 1.87 million edges/sec (incl time for L=tril(A)) -rate 1.88 million edges/sec (just tricount itself) -C=L*L time (saxpy): 2.962654 sec (nthreads: 2 speedup 1.79489) -tricount time: 2.965725 sec (saxpy method) -tri+prep time: 2.984754 sec (incl time to compute L) -compute C time: 2.962654 sec -reduce (C) time: 0.003071 sec -rate 3.35 million edges/sec (incl time for L=tril(A)) -rate 3.37 million edges/sec (just tricount itself) -C=L*L time (saxpy): 1.746472 sec (nthreads: 4 speedup 3.04479) -tricount time: 1.748662 sec (saxpy method) -tri+prep time: 1.767690 sec (incl time to compute L) -compute C time: 1.746472 sec -reduce (C) time: 0.002190 sec -rate 5.65 million edges/sec (incl time for L=tril(A)) -rate 5.71 million edges/sec (just tricount itself) -C=L*L time (saxpy): 1.784942 sec (nthreads: 8 speedup 2.97917) -tricount time: 1.785944 sec (saxpy method) -tri+prep time: 1.804972 sec (incl time to compute L) -compute C time: 1.784942 sec -reduce (C) time: 0.001002 sec -rate 5.53 million edges/sec (incl time for L=tril(A)) -rate 5.59 million edges/sec (just tricount itself) +triangles, method 3: 1330131 +C=L*L time (saxpy): 8.392654 sec +tricount time: 8.397451 sec (saxpy method) +tri+prep time: 8.417023 sec (incl time to compute L) +compute C time: 8.392654 sec +reduce (C) time: 0.004796 sec +rate 1.19 million edges/sec (incl time for L=tril(A)) +rate 1.19 million edges/sec (just tricount itself) +triangles, method 3: 1330131 +C=L*L time (saxpy): 3.096104 sec (nthreads: 2 speedup 2.71071) +tricount time: 3.099485 sec (saxpy method) +tri+prep time: 3.119057 sec (incl time to compute L) +compute C time: 3.096104 sec +reduce (C) time: 0.003381 sec +rate 3.20 million edges/sec (incl time for L=tril(A)) +rate 3.22 million edges/sec (just tricount itself) +triangles, method 3: 1330131 +C=L*L time (saxpy): 1.860165 sec (nthreads: 4 speedup 4.51178) +tricount time: 1.862493 sec (saxpy method) +tri+prep time: 1.882065 sec (incl time to compute L) +compute C time: 1.860165 sec +reduce (C) time: 0.002328 sec +rate 5.31 million edges/sec (incl time for L=tril(A)) +rate 5.36 million edges/sec (just tricount itself) +triangles, method 3: 1330131 +C=L*L time (saxpy): 2.169445 sec (nthreads: 8 speedup 3.86857) +tricount time: 2.170250 sec (saxpy method) +tri+prep time: 2.189823 sec (incl time to compute L) +compute C time: 2.169445 sec +reduce (C) time: 0.000806 sec +rate 4.56 million edges/sec (incl time for L=tril(A)) +rate 4.60 million edges/sec (just tricount itself) diff --git a/Demo/Output/wildtype_demo.out b/Demo/Output/wildtype_demo.out index 3fe69b0943..431e87a45f 100644 --- a/Demo/Output/wildtype_demo.out +++ b/Demo/Output/wildtype_demo.out @@ -353,8 +353,8 @@ The matrix D is not wild enough to print. This is supposed to fail, as a demo of GrB_error: GraphBLAS error: GrB_DOMAIN_MISMATCH -function: GrB_eWiseAdd_Matrix_BinaryOp (C, M, accum, add, A, B, desc) -incompatible type for z=wildtype_add(x,y): +function: GrB_Matrix_eWiseAdd_BinaryOp (C, M, accum, add, A, B, desc) +Incompatible type for z=wildtype_add(x,y): second input of type [float] cannot be typecast to y input of type [wildtype] diff --git a/Demo/Program/bfs_demo.c b/Demo/Program/bfs_demo.c index df49ad427f..7d48f0728d 100644 --- a/Demo/Program/bfs_demo.c +++ b/Demo/Program/bfs_demo.c @@ -55,7 +55,7 @@ int main (int argc, char **argv) double tic [2], t ; OK (GrB_init (GrB_NONBLOCKING)) ; int nthreads ; - OK (GxB_Global_Option_get (GxB_NTHREADS, &nthreads)) ; + OK (GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads)) ; fprintf (stderr, "bfs_demo: nthreads %d\n", nthreads) ; //-------------------------------------------------------------------------- @@ -92,7 +92,7 @@ int main (int argc, char **argv) // All methods give identical results, just using different methods GrB_Index s = 0 ; - GxB_Global_Option_set (GxB_NTHREADS, 2) ; + GxB_Global_Option_set (GxB_GLOBAL_NTHREADS, 2) ; switch (method) { @@ -142,21 +142,16 @@ int main (int argc, char **argv) OK (GrB_Vector_new (&is_reachable, GrB_BOOL, n)) ; OK (GrB_Vector_apply (is_reachable, NULL, NULL, GrB_IDENTITY_BOOL, v, NULL)) ; - OK (GrB_Vector_reduce_UINT64 (&nreachable, NULL, GxB_PLUS_INT32_MONOID, + OK (GrB_Vector_reduce_UINT64 (&nreachable, NULL, GrB_PLUS_MONOID_INT32, is_reachable, NULL)) ; OK (GrB_Vector_free (&is_reachable)) ; // OK (GrB_Vector_nvals (&nreachable, v)) ; printf ("nodes reachable from node %.16g: %.16g out of %.16g\n", (double) s, (double) nreachable, (double) n) ; -// // note the typecast to int32_t -// // using a predefined monoid instead, GrB_MAX_INT32_MONOID. -// OK (GrB_Monoid_new_INT32 (&max_monoid, GrB_MAX_INT32, -// (int32_t) INT32_MIN)) ; - // find the max BFS level int64_t nlevels = -1 ; - OK (GrB_Vector_reduce_INT64 (&nlevels, NULL, GxB_MAX_INT32_MONOID, + OK (GrB_Vector_reduce_INT64 (&nlevels, NULL, GrB_MAX_MONOID_INT32, v, NULL)) ; printf ("max BFS level: %.16g\n", (double) nlevels) ; @@ -196,8 +191,8 @@ int main (int argc, char **argv) { fprintf (stderr, "test failure!\n") ; printf ("test failure!\n") ; - GxB_Vector_fprint (v0, "v0", 3, stdout) ; - GxB_Vector_fprint (v , "v", 3, stdout) ; + GxB_Vector_fprint (v0, "v0", GxB_COMPLETE, stdout) ; + GxB_Vector_fprint (v , "v", GxB_COMPLETE, stdout) ; exit (1) ; } } diff --git a/Demo/Program/complex_demo.c b/Demo/Program/complex_demo.c index db15711caf..faf72b8b75 100644 --- a/Demo/Program/complex_demo.c +++ b/Demo/Program/complex_demo.c @@ -13,8 +13,6 @@ #include "graphblas_demos.h" -#if GxB_STDC_VERSION >= 201112L - //------------------------------------------------------------------------------ // print a complex matrix //------------------------------------------------------------------------------ @@ -34,11 +32,19 @@ void print_complex_matrix (GrB_Matrix A, char *name) "\n%% GraphBLAS matrix %s: nrows: %.16g ncols %.16g entries: %.16g\n", name, (double) nrows, (double) ncols, (double) nentries) ; - GrB_Index *I = malloc (MAX (nentries,1) * sizeof (GrB_Index)) ; - GrB_Index *J = malloc (MAX (nentries,1) * sizeof (GrB_Index)) ; - double complex *X = malloc (MAX (nentries,1) * sizeof (double complex)) ; + GrB_Index *I = (GrB_Index *) malloc (MAX (nentries,1) * sizeof (GrB_Index)); + GrB_Index *J = (GrB_Index *) malloc (MAX (nentries,1) * sizeof (GrB_Index)); + GxB_FC64_t *X = (GxB_FC64_t *) + malloc (MAX (nentries,1) * sizeof (GxB_FC64_t)) ; - GrB_Matrix_extractTuples_UDT (I, J, X, &nentries, A) ; + if (Complex == GxB_FC64) + { + GxB_Matrix_extractTuples_FC64 (I, J, X, &nentries, A) ; + } + else + { + GrB_Matrix_extractTuples_UDT (I, J, X, &nentries, A) ; + } printf ("%s = sparse (%.16g,%.16g) ;\n", name, (double) nrows, (double) ncols) ; @@ -65,11 +71,28 @@ int main (int argc, char **argv) GrB_Matrix A, B, C ; // initialize GraphBLAS and create the user-defined Complex type + GrB_Info info ; GrB_init (GrB_NONBLOCKING) ; int nthreads ; - GxB_Global_Option_get (GxB_NTHREADS, &nthreads) ; + GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads) ; fprintf (stderr, "complex_demo: nthreads: %d\n", nthreads) ; - Complex_init ( ) ; + + bool predefined = (argc > 1) ; + if (predefined) + { + fprintf (stderr, "Using pre-defined GxB_FC64 complex type\n") ; + } + else + { + fprintf (stderr, "Using user-defined Complex type\n") ; + } + + info = Complex_init (predefined) ; + if (info != GrB_SUCCESS) + { + fprintf (stderr, "Complex init failed: %s\n", GrB_error ( )) ; + abort ( ) ; + } // generate random matrices A and B simple_rand_seed (1) ; @@ -109,7 +132,7 @@ int main (int argc, char **argv) //------------------------------------------------------------------------------ -#else +#if 0 int main ( ) { diff --git a/Demo/Program/import_demo.c b/Demo/Program/import_demo.c index 60507be408..246667f1c3 100644 --- a/Demo/Program/import_demo.c +++ b/Demo/Program/import_demo.c @@ -23,7 +23,7 @@ int main (int argc, char **argv) GrB_Info info ; OK (GrB_init (GrB_NONBLOCKING)) ; int nthreads ; - OK (GxB_Global_Option_get (GxB_NTHREADS, &nthreads)) ; + OK (GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads)) ; fprintf (stderr, "import_demo: nthreads: %d\n", nthreads) ; //-------------------------------------------------------------------------- diff --git a/Demo/Program/kron_demo.c b/Demo/Program/kron_demo.c index f674d10889..b6e4d48ab4 100644 --- a/Demo/Program/kron_demo.c +++ b/Demo/Program/kron_demo.c @@ -52,7 +52,7 @@ int main (int argc, char **argv) OK (GrB_init (GrB_NONBLOCKING)) ; int nthreads ; - OK (GxB_Global_Option_get (GxB_NTHREADS, &nthreads)) ; + OK (GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads)) ; fprintf (stderr, "kron demo: nthreads %d\n", nthreads) ; // printf ("argc %d\n", argc) ; @@ -102,7 +102,8 @@ int main (int argc, char **argv) OK (GrB_Matrix_new (&C, GrB_FP64, anrows * bnrows, ancols * bncols)) ; simple_tic (tic) ; - OK (GxB_kron (C, NULL, NULL, GrB_TIMES_FP64, A, B, NULL)) ; + OK (GrB_Matrix_kronecker_BinaryOp (C, NULL, NULL, + GrB_TIMES_FP64, A, B, NULL)) ; t = simple_toc (tic) ; OK (GrB_Matrix_free (&A)) ; @@ -120,7 +121,7 @@ int main (int argc, char **argv) // note that integers of type GrB_Index should be printed with the // %PRIu64 format. - fprintf (stderr, "GraphBLAS GxB_kron:\n" + fprintf (stderr, "GraphBLAS GrB_kronecker:\n" "A: %" PRIu64 "-by-%" PRIu64 ", %" PRIu64 " entries.\n" "B: %" PRIu64 "-by-%" PRIu64 ", %" PRIu64 " entries.\n" "C: %" PRIu64 "-by-%" PRIu64 ", %" PRIu64 " entries.\n" diff --git a/Demo/Program/mis_demo.c b/Demo/Program/mis_demo.c index babc3f65d0..93a4f74778 100644 --- a/Demo/Program/mis_demo.c +++ b/Demo/Program/mis_demo.c @@ -77,14 +77,14 @@ GrB_Info mis_check_results //-------------------------------------------------------------------------- int64_t isize ; - OK (GrB_Vector_reduce_INT64 (&isize, NULL, GxB_PLUS_INT64_MONOID, + OK (GrB_Vector_reduce_INT64 (&isize, NULL, GrB_PLUS_MONOID_INT64, iset, NULL)) ; (*p_isize) = isize ; GrB_Index nvals ; OK (GrB_Vector_nvals (&nvals, iset)) ; - I = malloc (nvals * sizeof (GrB_Index)) ; - X = malloc (nvals * sizeof (float)) ; + I = (GrB_Index *) malloc (nvals * sizeof (GrB_Index)) ; + X = (float *) malloc (nvals * sizeof (float)) ; if (I == NULL || X == NULL) { @@ -119,9 +119,9 @@ GrB_Info mis_check_results OK (GrB_Matrix_extract (C, NULL, NULL, A, I, isize, I, isize, NULL)) ; OK (GrB_Matrix_nvals (&nvals, C)) ; - I2 = malloc (nvals * sizeof (GrB_Index)) ; - J2 = malloc (nvals * sizeof (GrB_Index)) ; - X2 = malloc (nvals * sizeof (bool)) ; + I2 = (GrB_Index *) malloc (nvals * sizeof (GrB_Index)) ; + J2 = (GrB_Index *) malloc (nvals * sizeof (GrB_Index)) ; + X2 = (bool *) malloc (nvals * sizeof (bool)) ; if (I2 == NULL || J2 == NULL || X2 == NULL) { printf ("out of memory\n") ; @@ -178,7 +178,7 @@ int main (int argc, char **argv) double tic [2], t1, t2 ; OK (GrB_init (GrB_NONBLOCKING)) ; int nthreads ; - OK (GxB_Global_Option_get (GxB_NTHREADS, &nthreads)) ; + OK (GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads)) ; fprintf (stderr, "\nmis_demo: nthreads: %d\n", nthreads) ; //-------------------------------------------------------------------------- diff --git a/Demo/Program/openmp_demo.c b/Demo/Program/openmp_demo.c index 727e5dc476..641cf90b93 100644 --- a/Demo/Program/openmp_demo.c +++ b/Demo/Program/openmp_demo.c @@ -23,8 +23,10 @@ #elif defined __GNUC__ #pragma GCC diagnostic ignored "-Wunknown-pragmas" #pragma GCC diagnostic ignored "-Wunused-parameter" +#if !defined ( __cplusplus ) #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" #endif +#endif #define NTHREADS 8 #define NTRIALS 10 @@ -126,7 +128,7 @@ int main (int argc, char **argv) // start GraphBLAS OK (GrB_init (GrB_NONBLOCKING)) ; int nthreads ; - OK (GxB_Global_Option_get (GxB_NTHREADS, &nthreads)) ; + OK (GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads)) ; fprintf (stderr, "openmp demo, nthreads %d\n", nthreads) ; // Determine which user-threading model is being used. diff --git a/Demo/Program/pagerank_demo.c b/Demo/Program/pagerank_demo.c index 4db9d4232e..294da64c55 100644 --- a/Demo/Program/pagerank_demo.c +++ b/Demo/Program/pagerank_demo.c @@ -52,7 +52,7 @@ int main (int argc, char **argv) double tic [2], t ; OK (GrB_init (GrB_NONBLOCKING)) ; int nthreads ; - OK (GxB_Global_Option_get (GxB_NTHREADS, &nthreads)) ; + OK (GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads)) ; fprintf (stderr, "\npagerank_demo: nthreads: %d\n", nthreads) ; printf ( "\npagerank_demo: nthreads: %d\n", nthreads) ; diff --git a/Demo/Program/reduce_demo.c b/Demo/Program/reduce_demo.c index 61be626c1e..af75779ee0 100644 --- a/Demo/Program/reduce_demo.c +++ b/Demo/Program/reduce_demo.c @@ -22,11 +22,11 @@ int main (void) // start GraphBLAS GrB_init (GrB_NONBLOCKING) ; int nthreads ; - GxB_Global_Option_get (GxB_NTHREADS, &nthreads) ; + GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads) ; printf ("demo: reduce a matrix to a scalar, nthreads: %d\n", nthreads) ; int nthreads_max ; - GxB_Global_Option_get (GxB_NTHREADS, &nthreads_max) ; + GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads_max) ; printf ("# of threads: %d\n", nthreads_max) ; #if defined ( _OPENMP ) @@ -40,9 +40,9 @@ int main (void) GrB_Matrix A ; GrB_Matrix_new (&A, GrB_INT64, nrows, ncols) ; - GrB_Index *I = malloc (nrows * ncols * sizeof (GrB_Index)) ; - GrB_Index *J = malloc (nrows * ncols * sizeof (GrB_Index)) ; - int64_t *X = malloc (nrows * ncols * sizeof (int64_t)) ; + GrB_Index *I = (GrB_Index *) malloc (nrows * ncols * sizeof (GrB_Index)) ; + GrB_Index *J = (GrB_Index *) malloc (nrows * ncols * sizeof (GrB_Index)) ; + int64_t *X = (int64_t *) malloc (nrows * ncols * sizeof (int64_t)) ; int64_t k ; #pragma omp parallel for num_threads(nthreads_max) schedule(static) @@ -78,11 +78,11 @@ int main (void) for (int nthreads = 1 ; nthreads <= nthreads_max ; nthreads++) { - GxB_Global_Option_set (GxB_NTHREADS, nthreads) ; + GxB_Global_Option_set (GxB_GLOBAL_NTHREADS, nthreads) ; #if defined ( _OPENMP ) double t = omp_get_wtime ( ) ; #endif - GrB_Matrix_reduce_UINT64 (&result, NULL, GxB_PLUS_INT64_MONOID, + GrB_Matrix_reduce_UINT64 (&result, NULL, GrB_PLUS_MONOID_INT64, A, NULL) ; #if defined ( _OPENMP ) t = omp_get_wtime ( ) - t ; @@ -92,7 +92,7 @@ int main (void) #endif } - printf ("result %"PRId64"\n", result) ; + printf ("result %" PRId64 "\n", result) ; // free everyting GrB_Matrix_free (&A) ; diff --git a/Demo/Program/simple_demo.c b/Demo/Program/simple_demo.c index 0812b1a1fc..9db4746bac 100644 --- a/Demo/Program/simple_demo.c +++ b/Demo/Program/simple_demo.c @@ -48,7 +48,7 @@ int main (void) double n = ((double) LEN) / 1e6 ; // calloc the space for more accurate timing - x = calloc (LEN, sizeof (double)) ; + x = (double *) calloc (LEN, sizeof (double)) ; if (x == NULL) { fprintf (stderr, "simple_demo: out of memory\n") ; diff --git a/Demo/Program/tri_demo.c b/Demo/Program/tri_demo.c index d9da5a9149..100b60401e 100644 --- a/Demo/Program/tri_demo.c +++ b/Demo/Program/tri_demo.c @@ -53,7 +53,7 @@ int main (int argc, char **argv) double tic [2], r1, r2 ; OK (GrB_init (GrB_NONBLOCKING)) ; int nthreads ; - OK (GxB_Global_Option_get (GxB_NTHREADS, &nthreads)) ; + OK (GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads)) ; fprintf (stderr, "tri_demo: nthreads %d\n", nthreads) ; printf ("--------------------------------------------------------------\n"); @@ -62,17 +62,19 @@ int main (int argc, char **argv) //-------------------------------------------------------------------------- // get_matrix reads in a boolean matrix. It could easily be changed to - // read in uint32 matrix instead, but this would affect the other GraphBLAS - // demos. So the time to typecast A = (uint32) C is added to the read + // read in int32 matrix instead, but this would affect the other GraphBLAS + // demos. So the time to typecast A = (int32) C is added to the read // time, not the prep time for triangle counting. simple_tic (tic) ; OK (get_matrix (&C, argc, argv, true, true)) ; GrB_Index n, nedges ; OK (GrB_Matrix_nrows (&n, C)) ; - // A = spones (C), and typecast to uint32 - OK (GrB_Matrix_new (&A, GrB_UINT32, n, n)) ; - OK (GrB_Matrix_apply (A, NULL, NULL, GxB_ONE_UINT32, C, NULL)) ; + GrB_Type ctype = GrB_INT32 ; + + // A = spones (C), and typecast to int32 + OK (GrB_Matrix_new (&A, ctype, n, n)) ; + OK (GrB_Matrix_apply (A, NULL, NULL, GxB_ONE_INT32, C, NULL)) ; double t_read = simple_toc (tic) ; printf ("\ntotal time to read A matrix: %14.6f sec\n", t_read) ; GrB_Matrix_free (&C) ; @@ -82,7 +84,7 @@ int main (int argc, char **argv) // U = triu (A,1) simple_tic (tic) ; OK (GxB_Scalar_setElement_INT64 (Thunk, (int64_t) 1)) ; - OK (GrB_Matrix_new (&U, GrB_UINT32, n, n)) ; + OK (GrB_Matrix_new (&U, ctype, n, n)) ; OK (GxB_Matrix_select (U, NULL, NULL, GxB_TRIU, A, Thunk, NULL)) ; OK (GrB_Matrix_nvals (&nedges, U)) ; printf ("\nn %.16g # edges %.16g\n", (double) n, (double) nedges) ; @@ -91,7 +93,7 @@ int main (int argc, char **argv) // L = tril (A,-1) simple_tic (tic) ; - OK (GrB_Matrix_new (&L, GrB_UINT32, n, n)) ; + OK (GrB_Matrix_new (&L, ctype, n, n)) ; OK (GxB_Scalar_setElement_INT64 (Thunk, (int64_t) (-1))) ; OK (GxB_Matrix_select (L, NULL, NULL, GxB_TRIL, A, Thunk, NULL)) ; double t_L = simple_toc (tic) ; @@ -117,7 +119,7 @@ int main (int argc, char **argv) for (int nthreads = 1 ; nthreads <= nthreads_max ; nthreads *= 2) { - GxB_Global_Option_set (GxB_NTHREADS, nthreads) ; + GxB_Global_Option_set (GxB_GLOBAL_NTHREADS, nthreads) ; double t_dot [2] ; OK (tricount (&(ntri2 [nthreads]), 5, NULL, NULL, L, U, t_dot)) ; @@ -130,7 +132,7 @@ int main (int argc, char **argv) } if (ntri2 [nthreads] != nt) { - printf ("error!\n") ; + printf ("error 5!\n") ; fprintf (stderr, "error!\n") ; exit (1) ; } @@ -170,7 +172,7 @@ int main (int argc, char **argv) for (int nthreads = 1 ; nthreads <= nthreads_max ; nthreads *= 2) { - GxB_Global_Option_set (GxB_NTHREADS, nthreads) ; + GxB_Global_Option_set (GxB_GLOBAL_NTHREADS, nthreads) ; double t_dot [2] ; OK (tricount (&(ntri2 [nthreads]), 6, NULL, NULL, L, U, t_dot)) ; @@ -179,7 +181,7 @@ int main (int argc, char **argv) // fprintf (stderr, "# triangles %.16g\n", (double) ntri2 [nthreads]) ; if (ntri2 [nthreads] != nt) { - printf ("error!\n") ; + printf ("error 6!\n") ; fprintf (stderr, "error!\n") ; exit (1) ; } @@ -223,13 +225,14 @@ int main (int argc, char **argv) for (int nthreads = 1 ; nthreads <= nthreads_max ; nthreads *= 2) { - GxB_Global_Option_set (GxB_NTHREADS, nthreads) ; + GxB_Global_Option_set (GxB_GLOBAL_NTHREADS, nthreads) ; double t_mark [2] = { 0, 0 } ; OK (tricount (&ntri1 [nthreads], 3, NULL, NULL, L, NULL, t_mark)) ; + printf ("triangles, method 3: %0.16g\n", (double) ntri1 [nthreads]) ; if (ntri1 [nthreads] != nt) { - printf ("error!\n") ; + printf ("error 3!\n") ; fprintf (stderr, "error!\n") ; exit (1) ; } diff --git a/Demo/Program/wildtype_demo.c b/Demo/Program/wildtype_demo.c index e35c7747ac..ed1f111f94 100644 --- a/Demo/Program/wildtype_demo.c +++ b/Demo/Program/wildtype_demo.c @@ -16,8 +16,12 @@ #pragma warning (disable: 58 167 144 177 181 186 188 589 593 869 981 1418 1419 1572 1599 2259 2282 2557 2547 3280 ) #elif defined __GNUC__ #pragma GCC diagnostic ignored "-Wunused-parameter" +#if defined ( __cplusplus ) +#pragma GCC diagnostic ignored "-Wwrite-strings" +#else #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" #endif +#endif //------------------------------------------------------------------------------ // the wildtype @@ -154,7 +158,7 @@ int main (void) // start GraphBLAS GrB_init (GrB_NONBLOCKING) ; int nthreads ; - GxB_Global_Option_get (GxB_NTHREADS, &nthreads) ; + GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads) ; fprintf (stderr, "wildtype demo: nthreads %d\n", nthreads) ; /* alternative method via #defines: @@ -228,7 +232,7 @@ int main (void) } int nthreads_max ; - GxB_Global_Option_get (GxB_NTHREADS, &nthreads_max) ; + GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads_max) ; fprintf (stderr, "max # of threads used internally: %d\n", nthreads_max) ; // create the WildType @@ -284,11 +288,13 @@ int main (void) // create the WildAdd operator GrB_BinaryOp WildAdd ; - GrB_BinaryOp_new (&WildAdd, wildtype_add, WildType, WildType, WildType) ; + GrB_BinaryOp_new (&WildAdd, + (GxB_binary_function) wildtype_add, WildType, WildType, WildType) ; // create the WildMult operator GrB_BinaryOp WildMult ; - GrB_BinaryOp_new (&WildMult, wildtype_mult, WildType, WildType, WildType) ; + GrB_BinaryOp_new (&WildMult, + (GxB_binary_function) wildtype_mult, WildType, WildType, WildType) ; // create a matrix B with B (7,2) = scalar2 GrB_Matrix B ; @@ -361,7 +367,7 @@ int main (void) wildtype_print_matrix (D, "D") ; // do something invalid - info = GrB_eWiseAdd_Matrix_BinaryOp (C, NULL, NULL, WildAdd, A, D, NULL) ; + info = GrB_Matrix_eWiseAdd_BinaryOp (C, NULL, NULL, WildAdd, A, D, NULL) ; if (info != GrB_SUCCESS) { printf ("\nThis is supposed to fail, as a demo of GrB_error:\n%s\n", diff --git a/Demo/README.txt b/Demo/README.txt index 19abcfbb18..b9ceb97c09 100644 --- a/Demo/README.txt +++ b/Demo/README.txt @@ -50,7 +50,7 @@ in Demo/Program: bfs_demo.c demo program to test bfs complex_demo.c demo program to test complex type import_demo.c demo program to test import/export - kron_demo.c demo program to test GxB_kron + kron_demo.c demo program to test GrB_kronecker mis_demo.c demo program to test mis tri_demo.c demo program to test tricount simple_demo.c demo program to test simple_rand and simple_timer diff --git a/Demo/Source/bfs5m.c b/Demo/Source/bfs5m.c index e2c454fd70..70f2fa1f71 100644 --- a/Demo/Source/bfs5m.c +++ b/Demo/Source/bfs5m.c @@ -57,8 +57,6 @@ GrB_Info bfs5m // BFS of a graph (using vector assign & reduce) GrB_Index n ; // # of nodes in the graph GrB_Vector q = NULL ; // nodes visited at each level GrB_Vector v = NULL ; // result vector - GrB_Monoid Lor = NULL ; // Logical-or monoid - GrB_Semiring Boolean = NULL ; // Boolean semiring GrB_Descriptor desc = NULL ; // Descriptor for vxm GrB_Matrix_nrows (&n, A) ; // n = # of rows of A @@ -69,8 +67,6 @@ GrB_Info bfs5m // BFS of a graph (using vector assign & reduce) GrB_Vector_new (&q, GrB_BOOL, n) ; // Vector q(n) = false GrB_Vector_setElement_BOOL (q, true, s) ; // q[s] = true, false elsewhere - GrB_Monoid_new_BOOL (&Lor, GrB_LOR, (bool) false) ; - GrB_Semiring_new (&Boolean, Lor, GrB_LAND) ; GrB_Descriptor_new (&desc) ; GrB_Descriptor_set (desc, GrB_MASK, GrB_COMP) ; // invert the mask GrB_Descriptor_set (desc, GrB_OUTP, GrB_REPLACE) ; // clear q first @@ -88,10 +84,10 @@ GrB_Info bfs5m // BFS of a graph (using vector assign & reduce) // q = q ||.&& A ; finds all the unvisited // successors from current q, using !v as the mask - GrB_vxm (q, v, NULL, Boolean, q, A, desc) ; + GrB_vxm (q, v, NULL, GrB_LOR_LAND_SEMIRING_BOOL, q, A, desc) ; // successor = ||(q) - GrB_Vector_reduce_BOOL (&successor, NULL, Lor, q, NULL) ; + GrB_Vector_reduce_BOOL (&successor, NULL, GrB_LOR_MONOID_BOOL, q, NULL) ; } // make v sparse @@ -101,8 +97,6 @@ GrB_Info bfs5m // BFS of a graph (using vector assign & reduce) *v_output = v ; // return result GrB_Vector_free (&q) ; - GrB_Monoid_free (&Lor) ; - GrB_Semiring_free (&Boolean) ; GrB_Descriptor_free (&desc) ; return (GrB_SUCCESS) ; diff --git a/Demo/Source/bfs5m_check.c b/Demo/Source/bfs5m_check.c index cc2a446834..4994c82e59 100644 --- a/Demo/Source/bfs5m_check.c +++ b/Demo/Source/bfs5m_check.c @@ -19,11 +19,6 @@ // instead of GrB_mxv. It now more closely matches the BFS example in the // GraphBLAS C API Specification. -// This version uses a predefined semiring (GxB_LOR_LAND_BOOL) and a predefined -// monoid (GxB_LOR_BOOL_MONOID), in GraphBLAS.h. It also checks the status of -// each call to GraphBLAS functions. These two changes are unrelated. Both -// change are made here to illustrate two different things. - // "OK(x)" macro calls a GraphBLAS method, and if it fails, prints the error, // frees workspace, and returns to the caller. It uses the FREE_ALL macro // to free the workspace @@ -101,10 +96,10 @@ GrB_Info bfs5m_check // BFS of a graph (using vector assign & reduce) // q = q ||.&& A ; finds all the unvisited // successors from current q, using !v as the mask - OK (GrB_vxm (q, v, NULL, GxB_LOR_LAND_BOOL, q, A, desc)) ; + OK (GrB_vxm (q, v, NULL, GrB_LOR_LAND_SEMIRING_BOOL, q, A, desc)) ; // successor = ||(q) - OK (GrB_Vector_reduce_BOOL (&successor, NULL, GxB_LOR_BOOL_MONOID, + OK (GrB_Vector_reduce_BOOL (&successor, NULL, GrB_LOR_MONOID_BOOL, q, NULL)) ; } diff --git a/Demo/Source/bfs6.c b/Demo/Source/bfs6.c index afb4e8d189..94e7ccc1a7 100644 --- a/Demo/Source/bfs6.c +++ b/Demo/Source/bfs6.c @@ -42,9 +42,6 @@ // Note the operator accesses a global variable outside the control of // GraphBLAS. This is safe, but care must be taken not to change the global // variable "level" while pending operations have yet to be completed. -// See the User Guide on GrB_wait, which forces completion of pending work -// on all matrices, and also methods that force completion on individual -// matries (GrB_Matrix_nvals in particular). int32_t bfs_level_global = 0 ; @@ -84,8 +81,6 @@ GrB_Info bfs6 // BFS of a graph (using apply) GrB_Index n ; // # of nodes in the graph GrB_Vector q = NULL ; // nodes visited at each level GrB_Vector v = NULL ; // result vector - GrB_Monoid Lor = NULL ; // Logical-or monoid - GrB_Semiring Boolean = NULL ; // Boolean semiring GrB_Descriptor desc = NULL ; // Descriptor for vxm GrB_UnaryOp apply_level = NULL ; // unary op: // z = f(x) = bfs_level_global @@ -98,15 +93,6 @@ GrB_Info bfs6 // BFS of a graph (using apply) GrB_Vector_new (&q, GrB_BOOL, n) ; // Vector q(n) = false GrB_Vector_setElement_BOOL (q, true, s) ; // q[s] = true, false elsewhere - // Note the typecast to bool. Otherwise an error is reported, since the - // _Generic function selects the wrong function (int32, not boolean). This - // is because of default integer promotion of function arguments in C. - GrB_Monoid_new_BOOL (&Lor, GrB_LOR, (bool) false) ; - - // The semiring uses "AND" as the multiply operator, and "OR" as the - // addititive monoid. - GrB_Semiring_new (&Boolean, Lor, GrB_LAND) ; - GrB_Descriptor_new (&desc) ; GrB_Descriptor_set (desc, GrB_MASK, GrB_COMP) ; // invert the mask GrB_Descriptor_set (desc, GrB_OUTP, GrB_REPLACE) ; // clear q first @@ -131,10 +117,10 @@ GrB_Info bfs6 // BFS of a graph (using apply) // q = q ||.&& A ; finds all the unvisited // successors from current q, using !v as the mask - GrB_vxm (q, v, NULL, Boolean, q, A, desc) ; + GrB_vxm (q, v, NULL, GrB_LOR_LAND_SEMIRING_BOOL, q, A, desc) ; // successor = ||(q) - GrB_Vector_reduce_BOOL (&successor, NULL, Lor, q, NULL) ; + GrB_Vector_reduce_BOOL (&successor, NULL, GrB_LOR_MONOID_BOOL, q, NULL) ; } // make v sparse @@ -144,8 +130,6 @@ GrB_Info bfs6 // BFS of a graph (using apply) *v_output = v ; // return result GrB_Vector_free (&q) ; - GrB_Monoid_free (&Lor) ; - GrB_Semiring_free (&Boolean) ; GrB_Descriptor_free (&desc) ; GrB_UnaryOp_free (&apply_level) ; diff --git a/Demo/Source/bfs6_check.c b/Demo/Source/bfs6_check.c index 892017be0c..465d0a0e8e 100644 --- a/Demo/Source/bfs6_check.c +++ b/Demo/Source/bfs6_check.c @@ -19,11 +19,6 @@ // instead of GrB_mxv. It now more closely matches the BFS example in the // GraphBLAS C API Specification. -// This version uses a predefined semiring (GxB_LOR_LAND_BOOL) and a predefined -// monoid (GxB_LOR_BOOL_MONOID), in GraphBLAS.h. It also checks the status of -// each call to GraphBLAS functions. These two changes are unrelated. Both -// change are made here to illustrate two different things. - // "OK(x)" macro calls a GraphBLAS method, and if it fails, prints the error, // frees workspace, and returns to the caller. It uses the FREE_ALL macro // to free the workspace @@ -58,9 +53,6 @@ // Note the operator accesses a global variable outside the control of // GraphBLAS. This is safe, but care must be taken not to change the global // variable "level" while pending operations have yet to be completed. -// See the User Guide on GrB_wait, which forces completion of pending work -// on all matrices, and also methods that force completion on individual -// matries (GrB_Matrix_nvals in particular). int32_t bfs_level2_global = 0 ; @@ -138,10 +130,10 @@ GrB_Info bfs6_check // BFS of a graph (using apply) // q' = q ||.&& A ; finds all the unvisited // successors from current q, using !v as the mask - OK (GrB_vxm (q, v, NULL, GxB_LOR_LAND_BOOL, q, A, desc)) ; + OK (GrB_vxm (q, v, NULL, GrB_LOR_LAND_SEMIRING_BOOL, q, A, desc)) ; // successor = ||(q) - GrB_Vector_reduce_BOOL (&successor, NULL, GxB_LOR_BOOL_MONOID, + GrB_Vector_reduce_BOOL (&successor, NULL, GrB_LOR_MONOID_BOOL, q, NULL) ; } diff --git a/Demo/Source/dpagerank.c b/Demo/Source/dpagerank.c index 02ee7abefd..6822210534 100644 --- a/Demo/Source/dpagerank.c +++ b/Demo/Source/dpagerank.c @@ -135,8 +135,10 @@ GrB_Info dpagerank // GrB_SUCCESS or error condition OK (drowscale (&C, A)) ; // C = scale A by out-degree // create unary operators - OK (GrB_UnaryOp_new (&op_scale, fscale, GrB_FP64, GrB_FP64)) ; - OK (GrB_UnaryOp_new (&op_div , fdiv, GrB_FP64, GrB_FP64)) ; + OK (GrB_UnaryOp_new (&op_scale, + (GxB_unary_function) fscale, GrB_FP64, GrB_FP64)) ; + OK (GrB_UnaryOp_new (&op_div , + (GxB_unary_function) fdiv, GrB_FP64, GrB_FP64)) ; //-------------------------------------------------------------------------- // iterate to compute the pagerank of each node @@ -147,7 +149,7 @@ GrB_Info dpagerank // GrB_SUCCESS or error condition // r = ((c*r) * C) + (a * sum (r)) ; // s = a * sum (r) ; - OK (GrB_Vector_reduce_FP64 (&s, NULL, GxB_PLUS_FP64_MONOID, r, NULL)) ; + OK (GrB_Vector_reduce_FP64 (&s, NULL, GrB_PLUS_MONOID_FP64, r, NULL)) ; s *= a ; // r = c * r @@ -166,7 +168,7 @@ GrB_Info dpagerank // GrB_SUCCESS or error condition //-------------------------------------------------------------------------- // s = sum (r) - OK (GrB_Vector_reduce_FP64 (&s, NULL, GxB_PLUS_FP64_MONOID, r, NULL)) ; + OK (GrB_Vector_reduce_FP64 (&s, NULL, GrB_PLUS_MONOID_FP64, r, NULL)) ; // r = r / s OK (GrB_Vector_apply (r, NULL, NULL, op_div, r, NULL)) ; @@ -178,8 +180,8 @@ GrB_Info dpagerank // GrB_SUCCESS or error condition // [r,irank] = sort (r, 'descend') ; // [I,X] = find (r) ; - X = malloc (n * sizeof (double)) ; - I = malloc (n * sizeof (GrB_Index)) ; + X = (double *) malloc (n * sizeof (double)) ; + I = (GrB_Index *) malloc (n * sizeof (GrB_Index)) ; CHECK (I != NULL && X != NULL, GrB_OUT_OF_MEMORY) ; GrB_Index nvals = n ; OK (GrB_Vector_extractTuples_FP64 (I, X, &nvals, r)) ; @@ -191,7 +193,7 @@ GrB_Info dpagerank // GrB_SUCCESS or error condition GrB_Vector_free (&r) ; // P = struct (X,I) - P = malloc (n * sizeof (PageRank)) ; + P = (PageRank *) malloc (n * sizeof (PageRank)) ; CHECK (P != NULL, GrB_OUT_OF_MEMORY) ; for (int64_t k = 0 ; k < nvals ; k++) { diff --git a/Demo/Source/dpagerank2.c b/Demo/Source/dpagerank2.c index 1e85a4d793..a5d68a6a32 100644 --- a/Demo/Source/dpagerank2.c +++ b/Demo/Source/dpagerank2.c @@ -262,20 +262,23 @@ GrB_Info dpagerank2 // GrB_SUCCESS or error condition // create the new Page type OK (GrB_Type_new (&PageRank_type, sizeof (pagerank_type))) ; + #define U (GxB_unary_function) + #define B (GxB_binary_function) + // create the unary operator to initialize the PageRank_type of each node - OK (GrB_UnaryOp_new (&PageRank_init, init_page, PageRank_type, GrB_FP64)) ; + OK (GrB_UnaryOp_new (&PageRank_init, U init_page, PageRank_type, GrB_FP64)); // create PageRank_accum - OK (GrB_BinaryOp_new (&PageRank_accum, pagerank_accum, + OK (GrB_BinaryOp_new (&PageRank_accum, B pagerank_accum, PageRank_type, PageRank_type, PageRank_type)) ; // create PageRank_add operator and monoid - OK (GrB_BinaryOp_new (&PageRank_add, pagerank_add, + OK (GrB_BinaryOp_new (&PageRank_add, B pagerank_add, PageRank_type, PageRank_type, PageRank_type)) ; OK (GrB_Monoid_new_UDT (&PageRank_monoid, PageRank_add, &pagerank_zero)) ; // create PageRank_multiply operator - OK (GrB_BinaryOp_new (&PageRank_multiply, pagerank_multiply, + OK (GrB_BinaryOp_new (&PageRank_multiply, B pagerank_multiply, PageRank_type, PageRank_type, GrB_BOOL)) ; // create PageRank_semiring @@ -283,14 +286,14 @@ GrB_Info dpagerank2 // GrB_SUCCESS or error condition PageRank_multiply)) ; // create unary operator that typecasts the PageRank_type to double - OK (GrB_UnaryOp_new (&PageRank_get, pagerank_get_rank, GrB_FP64, + OK (GrB_UnaryOp_new (&PageRank_get, U pagerank_get_rank, GrB_FP64, PageRank_type)) ; // create unary operator that scales the rank by pagerank_rsum - OK (GrB_UnaryOp_new (&PageRank_div, pagerank_div, GrB_FP64, GrB_FP64)) ; + OK (GrB_UnaryOp_new (&PageRank_div, U pagerank_div, GrB_FP64, GrB_FP64)) ; // create PageRank_diff operator - OK (GrB_BinaryOp_new (&PageRank_diff, pagerank_diff, + OK (GrB_BinaryOp_new (&PageRank_diff, B pagerank_diff, PageRank_type, PageRank_type, PageRank_type)) ; //-------------------------------------------------------------------------- @@ -349,7 +352,7 @@ GrB_Info dpagerank2 // GrB_SUCCESS or error condition desc)) ; // compute pagerank_rdiff = sum ((r - rnew).^2) - OK (GrB_eWiseAdd_Vector_BinaryOp (rdiff, NULL, NULL, PageRank_diff, + OK (GrB_Vector_eWiseAdd_BinaryOp (rdiff, NULL, NULL, PageRank_diff, r, rnew, NULL)) ; pagerank_type rsum ; OK (GrB_Vector_reduce_UDT (&rsum, NULL, PageRank_monoid, rdiff, NULL)) ; @@ -376,7 +379,7 @@ GrB_Info dpagerank2 // GrB_SUCCESS or error condition GrB_Vector_free (&r) ; // pagerank_rsum = sum (rdouble) - OK (GrB_Vector_reduce_FP64 (&pagerank_rsum, NULL, GxB_PLUS_FP64_MONOID, + OK (GrB_Vector_reduce_FP64 (&pagerank_rsum, NULL, GrB_PLUS_MONOID_FP64, rdouble, NULL)) ; // could also do this with GrB_vxm, with a 1-by-1 matrix @@ -394,8 +397,8 @@ GrB_Info dpagerank2 // GrB_SUCCESS or error condition // [r,irank] = sort (r, 'descend') ; // [I,X] = find (r) ; - X = malloc (n * sizeof (double)) ; - I = malloc (n * sizeof (GrB_Index)) ; + X = (double *) malloc (n * sizeof (double)) ; + I = (GrB_Index *) malloc (n * sizeof (GrB_Index)) ; CHECK (I != NULL && X != NULL, GrB_OUT_OF_MEMORY) ; GrB_Index nvals = n ; OK (GrB_Vector_extractTuples_FP64 (I, X, &nvals, rdouble)) ; @@ -404,7 +407,7 @@ GrB_Info dpagerank2 // GrB_SUCCESS or error condition GrB_Vector_free (&rdouble) ; // P = struct (X,I) - P = malloc (n * sizeof (PageRank)) ; + P = (PageRank *) malloc (n * sizeof (PageRank)) ; CHECK (P != NULL, GrB_OUT_OF_MEMORY) ; int64_t k ; for (k = 0 ; k < nvals ; k++) diff --git a/Demo/Source/drowscale.c b/Demo/Source/drowscale.c index b6e4e52c0a..246956293e 100644 --- a/Demo/Source/drowscale.c +++ b/Demo/Source/drowscale.c @@ -100,8 +100,8 @@ GrB_Info drowscale // GrB_SUCCESS or error condition // row i of A has no entries. // [I,~,X] = find (dout) ; - I = malloc ((n+1) * sizeof (GrB_Index)) ; - X = malloc ((n+1) * sizeof (double)) ; + I = (GrB_Index *) malloc ((n+1) * sizeof (GrB_Index)) ; + X = (double *) malloc ((n+1) * sizeof (double)) ; CHECK (I != NULL && X != NULL, GrB_OUT_OF_MEMORY) ; GrB_Index nvals = n ; OK (GrB_Vector_extractTuples_FP64 (I, X, &nvals, dout)) ; diff --git a/Demo/Source/ipagerank.c b/Demo/Source/ipagerank.c index 241d305ac2..485c9dd024 100644 --- a/Demo/Source/ipagerank.c +++ b/Demo/Source/ipagerank.c @@ -178,8 +178,10 @@ GrB_Info ipagerank // GrB_SUCCESS or error condition OK (irowscale (&C, A)) ; // C = scale A by out-degree // create unary operators - OK (GrB_UnaryOp_new (&op_scale, iscale, GrB_UINT64, GrB_UINT64)) ; - OK (GrB_UnaryOp_new (&op_div, idiv, GrB_UINT64, GrB_UINT64)) ; + OK (GrB_UnaryOp_new (&op_scale, + (GxB_unary_function) iscale, GrB_UINT64, GrB_UINT64)) ; + OK (GrB_UnaryOp_new (&op_div, + (GxB_unary_function) idiv, GrB_UINT64, GrB_UINT64)) ; //-------------------------------------------------------------------------- // iterate to compute the pagerank of each node @@ -194,7 +196,7 @@ GrB_Info ipagerank // GrB_SUCCESS or error condition // s = ia * sum (r) ; uint64_t s ; - OK (GrB_Vector_reduce_UINT64 (&s, NULL, GxB_PLUS_UINT64_MONOID, + OK (GrB_Vector_reduce_UINT64 (&s, NULL, GrB_PLUS_MONOID_UINT64, r, NULL)) ; s = s * ia ; @@ -222,8 +224,8 @@ GrB_Info ipagerank // GrB_SUCCESS or error condition // [r,irank] = sort (r, 'descend') ; // [I,X] = find (r) ; - X = malloc (n * sizeof (uint64_t)) ; - I = malloc (n * sizeof (GrB_Index)) ; + X = (uint64_t *) malloc (n * sizeof (uint64_t)) ; + I = (GrB_Index *) malloc (n * sizeof (GrB_Index)) ; CHECK (I != NULL && X != NULL, GrB_OUT_OF_MEMORY) ; GrB_Index nvals = n ; OK (GrB_Vector_extractTuples_UINT64 (I, X, &nvals, r)) ; @@ -235,7 +237,7 @@ GrB_Info ipagerank // GrB_SUCCESS or error condition GrB_Vector_free (&r) ; // P = struct (X,I) - P = malloc (n * sizeof (iPageRank)) ; + P = (iPageRank *) malloc (n * sizeof (iPageRank)) ; CHECK (P != NULL, GrB_OUT_OF_MEMORY) ; for (int64_t k = 0 ; k < nvals ; k++) { diff --git a/Demo/Source/irowscale.c b/Demo/Source/irowscale.c index db0910e668..860e82819c 100644 --- a/Demo/Source/irowscale.c +++ b/Demo/Source/irowscale.c @@ -103,8 +103,8 @@ GrB_Info irowscale // GrB_SUCCESS or error condition // if row i of A has no entries. // [I,~,X] = find (dout) ; - I = malloc ((n+1) * sizeof (GrB_Index)) ; - X = malloc ((n+1) * sizeof (uint64_t)) ; + I = (GrB_Index *) malloc ((n+1) * sizeof (GrB_Index)) ; + X = (uint64_t *) malloc ((n+1) * sizeof (uint64_t)) ; CHECK (I != NULL && X != NULL, GrB_OUT_OF_MEMORY) ; GrB_Index nvals = n ; OK (GrB_Vector_extractTuples_UINT64 (I, X, &nvals, dout)) ; diff --git a/Demo/Source/isequal.c b/Demo/Source/isequal.c index 1429cf9184..1051a0e4c4 100644 --- a/Demo/Source/isequal.c +++ b/Demo/Source/isequal.c @@ -33,7 +33,6 @@ { \ /* error occured: free workspace and return */ \ GrB_Matrix_free (&C) ; \ - GrB_Monoid_free (&monoid) ; \ return (info) ; \ } \ } @@ -53,7 +52,6 @@ GrB_Info isequal_type // return GrB_SUCCESS if successful { GrB_Matrix C = NULL ; - GrB_Monoid monoid = NULL ; GrB_Index nrows1, ncols1, nrows2, ncols2, nvals, nvals1, nvals2 ; if (result == NULL) @@ -91,7 +89,7 @@ GrB_Info isequal_type // return GrB_SUCCESS if successful // C = A .* B, where the pattern of C is the intersection of A and B OK (GrB_Matrix_new (&C, GrB_BOOL, nrows1, ncols1)) ; - OK (GrB_eWiseMult_Matrix_BinaryOp (C, NULL, NULL, op, A, B, NULL)) ; + OK (GrB_Matrix_eWiseMult_BinaryOp (C, NULL, NULL, op, A, B, NULL)) ; // ensure C has the same number of entries as A and B OK (GrB_Matrix_nvals (&nvals, C)) ; @@ -102,19 +100,11 @@ GrB_Info isequal_type // return GrB_SUCCESS if successful return (GrB_SUCCESS) ; } - #ifdef GxB_SUITESPARSE_GRAPHBLAS - // SuiteSparse has a predefined boolean AND monoid - monoid = GxB_LAND_BOOL_MONOID ; - #else - OK (GrB_Monoid_new_BOOL (&monoid, GrB_LAND, true)) ; - #endif - // result = and (C) - OK (GrB_Matrix_reduce_BOOL (result, NULL, monoid, C, NULL)) ; + OK (GrB_Matrix_reduce_BOOL (result, NULL, GrB_LAND_MONOID_BOOL, C, NULL)) ; // free workspace and return result GrB_Matrix_free (&C) ; - GrB_Monoid_free (&monoid) ; return (GrB_SUCCESS) ; } @@ -135,7 +125,6 @@ GrB_Info isequal // return GrB_SUCCESS if successful ) { GrB_Matrix C = NULL ; - GrB_Monoid monoid = NULL ; GrB_Type atype, btype ; GrB_BinaryOp op ; @@ -167,6 +156,8 @@ GrB_Info isequal // return GrB_SUCCESS if successful else if (atype == GrB_UINT64) op = GrB_EQ_UINT64 ; else if (atype == GrB_FP32 ) op = GrB_EQ_FP32 ; else if (atype == GrB_FP64 ) op = GrB_EQ_FP64 ; + else if (atype == GxB_FC32 ) op = GxB_EQ_FC32 ; + else if (atype == GxB_FC64 ) op = GxB_EQ_FC64 ; else op = userop ; // A and B are user-defined // check the size, pattern, and values of A and B diff --git a/Demo/Source/mis.c b/Demo/Source/mis.c index 5ae361a85a..7942852327 100644 --- a/Demo/Source/mis.c +++ b/Demo/Source/mis.c @@ -57,10 +57,7 @@ GrB_Info mis // compute a maximal independent set GrB_Vector new_members = NULL ; // set of new members to iset GrB_Vector new_neighbors = NULL ; // new neighbors to new iset members GrB_Vector candidates = NULL ; // candidate members to iset - GrB_Monoid Max = NULL ; GrB_Semiring maxSelect1st = NULL ; // Max/Select1st "semiring" - GrB_Monoid Lor = NULL ; - GrB_Semiring Boolean = NULL ; // Boolean semiring GrB_Descriptor r_desc = NULL ; GrB_Descriptor sr_desc = NULL ; GrB_BinaryOp set_random = NULL ; @@ -80,12 +77,7 @@ GrB_Info mis // compute a maximal independent set GrB_Vector_new (&iset, GrB_BOOL, n) ; // create the maxSelect1st semiring - GrB_Monoid_new_FP64 (&Max, GrB_MAX_FP64, (double) 0.0) ; - GrB_Semiring_new (&maxSelect1st, Max, GrB_FIRST_FP64) ; - - // create the OR-AND-BOOL semiring - GrB_Monoid_new_BOOL (&Lor, GrB_LOR, (bool) false) ; - GrB_Semiring_new (&Boolean, Lor, GrB_LAND) ; + GrB_Semiring_new (&maxSelect1st, GrB_MAX_MONOID_FP64, GrB_FIRST_FP64) ; // descriptor: C_replace GrB_Descriptor_new (&r_desc) ; @@ -132,7 +124,7 @@ GrB_Info mis // compute a maximal independent set // GrB_Vector_apply (prob, candidates, NULL, set_random, degrees, // r_desc) ; prand_xget (X, Seed) ; - GrB_eWiseMult_Vector_BinaryOp (prob, candidates, NULL, set_random, + GrB_Vector_eWiseMult_BinaryOp (prob, candidates, NULL, set_random, degrees, X, r_desc) ; // compute the max probability of all neighbors @@ -140,11 +132,11 @@ GrB_Info mis // compute a maximal independent set prob, A, r_desc) ; // select node if its probability is > than all its active neighbors - GrB_eWiseAdd_Vector_BinaryOp (new_members, NULL, NULL, GrB_GT_FP64, + GrB_Vector_eWiseAdd_BinaryOp (new_members, NULL, NULL, GrB_GT_FP64, prob, neighbor_max, NULL) ; // add new members to independent set. - GrB_eWiseAdd_Vector_BinaryOp (iset, NULL, NULL, GrB_LOR, iset, + GrB_Vector_eWiseAdd_BinaryOp (iset, NULL, NULL, GrB_LOR, iset, new_members, NULL) ; // remove new members from set of candidates c = c & !new @@ -155,7 +147,7 @@ GrB_Info mis // compute a maximal independent set if (nvals == 0) { break ; } // early exit condition // Neighbors of new members can also be removed from candidates - GrB_vxm (new_neighbors, candidates, NULL, Boolean, + GrB_vxm (new_neighbors, candidates, NULL, GrB_LOR_LAND_SEMIRING_BOOL, new_members, A, NULL) ; GrB_Vector_apply (candidates, new_neighbors, NULL, GrB_IDENTITY_BOOL, candidates, sr_desc) ; @@ -179,10 +171,7 @@ GrB_Info mis // compute a maximal independent set GrB_Vector_free (&new_members) ; GrB_Vector_free (&new_neighbors) ; GrB_Vector_free (&candidates) ; - GrB_Monoid_free (&Max) ; GrB_Semiring_free (&maxSelect1st) ; - GrB_Monoid_free (&Lor) ; - GrB_Semiring_free (&Boolean) ; GrB_Descriptor_free (&r_desc) ; GrB_Descriptor_free (&sr_desc) ; GrB_BinaryOp_free (&set_random) ; diff --git a/Demo/Source/mis_check.c b/Demo/Source/mis_check.c index 3e8226c634..d469910d0f 100644 --- a/Demo/Source/mis_check.c +++ b/Demo/Source/mis_check.c @@ -25,10 +25,7 @@ #ifdef GxB_SUITESPARSE_GRAPHBLAS // use predefined semirings. They are safe to free, // so the FREE_ALL macro can be used as-is in either case. - #define Max GxB_MAX_FP64_MONOID #define maxSelect1st GxB_MAX_FIRST_FP64 - #define Lor GxB_LOR_BOOL_MONOID - #define Boolean GxB_LOR_LAND_BOOL #endif // "OK(x)" macro defined in graphblas_demos.h calls a GraphBLAS method, and if @@ -41,10 +38,7 @@ GrB_Vector_free (&new_members) ; \ GrB_Vector_free (&new_neighbors) ; \ GrB_Vector_free (&candidates) ; \ - GrB_Monoid_free (&Max) ; \ GrB_Semiring_free (&maxSelect1st) ; \ - GrB_Monoid_free (&Lor) ; \ - GrB_Semiring_free (&Boolean) ; \ GrB_Descriptor_free (&r_desc) ; \ GrB_Descriptor_free (&sr_desc) ; \ GrB_BinaryOp_free (&set_random) ; \ @@ -95,10 +89,7 @@ GrB_Info mis_check // compute a maximal independent set GrB_Vector new_neighbors = NULL ; // new neighbors to new iset members GrB_Vector candidates = NULL ; // candidate members to iset #ifndef GxB_SUITESPARSE_GRAPHBLAS - GrB_Monoid Max = NULL ; GrB_Semiring maxSelect1st = NULL ; // Max/Select1st "semiring" - GrB_Monoid Lor = NULL ; - GrB_Semiring Boolean = NULL ; // Boolean semiring #endif GrB_Descriptor r_desc = NULL ; GrB_Descriptor sr_desc = NULL ; @@ -123,12 +114,7 @@ GrB_Info mis_check // compute a maximal independent set #ifndef GxB_SUITESPARSE_GRAPHBLAS // create the maxSelect1st semiring - OK (GrB_Monoid_new_FP64 (&Max, GrB_MAX_FP64, (double) 0.0)) ; - OK (GrB_Semiring_new (&maxSelect1st, Max, GrB_FIRST_FP64)) ; - - // create the OR-AND-BOOL semiring - OK (GrB_Monoid_new_BOOL (&Lor, GrB_LOR, (bool) false)) ; - OK (GrB_Semiring_new (&Boolean, Lor, GrB_LAND)) ; + OK (GrB_Semiring_new (&maxSelect1st, GrB_MAX_MONOID_FP64, GrB_FIRST_FP64)) ; #endif // descriptor: C_replace @@ -178,7 +164,7 @@ GrB_Info mis_check // compute a maximal independent set // compute a random probability scaled by inverse of degree OK (prand_xget (X, Seed)) ; - OK (GrB_eWiseMult_Vector_BinaryOp (prob, candidates, NULL, set_random, + OK (GrB_Vector_eWiseMult_BinaryOp (prob, candidates, NULL, set_random, degrees, X, r_desc)) ; // compute the max probability of all neighbors @@ -186,11 +172,11 @@ GrB_Info mis_check // compute a maximal independent set prob, A, r_desc)) ; // select node if its probability is > than all its active neighbors - OK (GrB_eWiseAdd_Vector_BinaryOp (new_members, NULL, NULL, GrB_GT_FP64, + OK (GrB_Vector_eWiseAdd_BinaryOp (new_members, NULL, NULL, GrB_GT_FP64, prob, neighbor_max, NULL)) ; // add new members to independent set. - OK (GrB_eWiseAdd_Vector_BinaryOp (iset, NULL, NULL, GrB_LOR, iset, + OK (GrB_Vector_eWiseAdd_BinaryOp (iset, NULL, NULL, GrB_LOR, iset, new_members, NULL)) ; // remove new members from set of candidates c = c & !new @@ -201,8 +187,8 @@ GrB_Info mis_check // compute a maximal independent set if (nvals == 0) { break ; } // early exit condition // Neighbors of new members can also be removed from candidates - OK (GrB_vxm (new_neighbors, candidates, NULL, Boolean, - new_members, A, NULL)) ; + OK (GrB_vxm (new_neighbors, candidates, NULL, + GrB_LOR_LAND_SEMIRING_BOOL, new_members, A, NULL)) ; OK (GrB_Vector_apply (candidates, new_neighbors, NULL, GrB_IDENTITY_BOOL, candidates, sr_desc)) ; diff --git a/Demo/Source/prand.c b/Demo/Source/prand.c index 5d2ce9e482..745080cc55 100644 --- a/Demo/Source/prand.c +++ b/Demo/Source/prand.c @@ -212,8 +212,8 @@ GrB_Info prand_seed OK (GrB_Vector_new (Seed, prand_type, n)) ; // allocate the I and X arrays - I = malloc ((n+1) * sizeof (GrB_Index)) ; - X = malloc ((n+1) * sizeof (prand_t)) ; + I = (GrB_Index *) malloc ((n+1) * sizeof (GrB_Index)) ; + X = (prand_t *) malloc ((n+1) * sizeof (prand_t)) ; if (I == NULL || X == NULL) { PRAND_FREE_ALL ; diff --git a/Demo/Source/random_matrix.c b/Demo/Source/random_matrix.c index 1cd376a823..7656ae93bd 100644 --- a/Demo/Source/random_matrix.c +++ b/Demo/Source/random_matrix.c @@ -58,7 +58,6 @@ GrB_Info random_matrix // create a random double-precision matrix if (A_complex) { - #if GxB_STDC_VERSION >= 201112L // Areal = real random matrix OK (random_matrix (&Areal, make_symmetric, no_self_edges, nrows, ncols, nedges, method, false)) ; @@ -75,10 +74,6 @@ GrB_Info random_matrix // create a random double-precision matrix A = NULL ; FREE_ALL ; return (GrB_SUCCESS) ; - #else - printf ("complex data type not available\n") ; - return (GrB_INVALID_VALUE) ; - #endif } //-------------------------------------------------------------------------- @@ -141,9 +136,9 @@ GrB_Info random_matrix // create a random double-precision matrix // by the mode (blocking or non-blocking). int64_t s = ((make_symmetric) ? 2 : 1) * nedges + 1 ; - I = malloc (s * sizeof (GrB_Index)) ; - J = malloc (s * sizeof (GrB_Index)) ; - X = malloc (s * sizeof (double )) ; + I = (GrB_Index *) malloc (s * sizeof (GrB_Index)) ; + J = (GrB_Index *) malloc (s * sizeof (GrB_Index)) ; + X = (double *) malloc (s * sizeof (double )) ; if (I == NULL || J == NULL || X == NULL) { // out of memory FREE_ALL ; diff --git a/Demo/Source/read_matrix.c b/Demo/Source/read_matrix.c index a78b3b861f..b71cb7db4a 100644 --- a/Demo/Source/read_matrix.c +++ b/Demo/Source/read_matrix.c @@ -80,8 +80,8 @@ GrB_Info read_matrix // read a double-precision or boolean matrix //-------------------------------------------------------------------------- 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 ; + GrB_Index *I = (GrB_Index *) malloc (len * sizeof (GrB_Index)), *I2 = NULL ; + GrB_Index *J = (GrB_Index *) malloc (len * sizeof (GrB_Index)), *J2 = NULL ; void *X = malloc (len * xsize) ; bool *Xbool ; double *Xdouble ; @@ -109,8 +109,8 @@ GrB_Info read_matrix // read a double-precision or boolean matrix 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)) ; + I2 = (GrB_Index *) realloc (I, 2 * len * sizeof (GrB_Index)) ; + J2 = (GrB_Index *) realloc (J, 2 * len * sizeof (GrB_Index)) ; X2 = realloc (X, 2 * len * xsize) ; if (I2 == NULL || J2 == NULL || X2 == NULL) { @@ -268,7 +268,7 @@ GrB_Info read_matrix // read a double-precision or boolean matrix double tic [2], t ; simple_tic (tic) ; OK (GrB_Matrix_new (&A, xtype, nrows, nrows)) ; - OK (GrB_eWiseAdd_Matrix_BinaryOp (A, NULL, NULL, xop, C, C, dt2)) ; + OK (GrB_Matrix_eWiseAdd_BinaryOp (A, NULL, NULL, xop, C, C, dt2)) ; OK (GrB_Matrix_free (&C)) ; if (boolean) @@ -279,7 +279,8 @@ GrB_Info read_matrix // read a double-precision or boolean matrix else { OK (GrB_Matrix_new (&C, xtype, nrows, nrows)) ; - OK (GrB_UnaryOp_new (&scale2_op, scale2, xtype, xtype)) ; + OK (GrB_UnaryOp_new (&scale2_op, + (GxB_unary_function) scale2, xtype, xtype)) ; OK (GrB_Matrix_apply (C, NULL, NULL, scale2_op, A, NULL)) ; OK (GrB_Matrix_free (&A)) ; OK (GrB_UnaryOp_free (&scale2_op)) ; diff --git a/Demo/Source/tricount.c b/Demo/Source/tricount.c index 533040571e..b48434e6b3 100644 --- a/Demo/Source/tricount.c +++ b/Demo/Source/tricount.c @@ -45,7 +45,7 @@ // relevant references. // All input matrices should have binary values (0 and 1). Any type will work, -// but uint32 is recommended for fastest results since that is the type used +// but int32 is recommended for fastest results since that is the type used // here for the semiring. GraphBLAS will do typecasting internally, but that // takes extra time. @@ -71,7 +71,7 @@ // two: unary function for GrB_apply //------------------------------------------------------------------------------ -void two (uint32_t *z, const uint32_t *x) +void two (int32_t *z, const int32_t *x) { (*z) = (double) (((*x) == 2) ? 1 : 0) ; } @@ -107,22 +107,25 @@ GrB_Info tricount // count # of triangles GrB_Descriptor d = NULL ; OK (GrB_Descriptor_new (&d)) ; + GrB_Semiring semiring = GrB_PLUS_TIMES_SEMIRING_INT32 ; + GrB_Type ctype = GrB_INT32 ; + switch (method) { case 0: // minitri: ntri = nnz (A*E == 2) / 3 OK (GrB_Matrix_nrows (&n, A)) ; OK (GrB_Matrix_ncols (&ne, E)) ; - OK (GrB_Matrix_new (&C, GrB_UINT32, n, ne)) ; + OK (GrB_Matrix_new (&C, ctype, n, ne)) ; // mxm: outer product method, no mask OK (GxB_Desc_set (d, GxB_AxB_METHOD, GxB_AxB_GUSTAVSON)) ; OK (GrB_mxm (C, NULL, NULL, GxB_PLUS_TIMES_UINT32, A, E, d)) ; t [0] = simple_toc (tic) ; simple_tic (tic) ; - OK (GrB_UnaryOp_new (&Two, two, GrB_UINT32, GrB_UINT32)) ; - OK (GrB_Matrix_new (&S, GrB_UINT32, n, ne)) ; + OK (GrB_UnaryOp_new (&Two, (GxB_unary_function) two, ctype, ctype)); + OK (GrB_Matrix_new (&S, ctype, n, ne)) ; OK (GrB_Matrix_apply (S, NULL, NULL, Two, C, NULL)) ; - OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GxB_PLUS_INT64_MONOID, + OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GrB_PLUS_MONOID_INT64, S, NULL)) ; ntri /= 3 ; break ; @@ -130,13 +133,13 @@ GrB_Info tricount // count # of triangles case 1: // Burkhardt: ntri = sum (sum ((A^2) .* A)) / 6 OK (GrB_Matrix_nrows (&n, A)) ; - OK (GrB_Matrix_new (&C, GrB_UINT32, n, n)) ; + OK (GrB_Matrix_new (&C, ctype, n, n)) ; // mxm: outer product method, with mask OK (GxB_Desc_set (d, GxB_AxB_METHOD, GxB_AxB_GUSTAVSON)) ; - OK (GrB_mxm (C, A, NULL, GxB_PLUS_TIMES_UINT32, A, A, d)) ; + OK (GrB_mxm (C, A, NULL, semiring, A, A, d)) ; t [0] = simple_toc (tic) ; simple_tic (tic) ; - OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GxB_PLUS_INT64_MONOID, + OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GrB_PLUS_MONOID_INT64, C, NULL)) ; ntri /= 6 ; break ; @@ -144,13 +147,13 @@ GrB_Info tricount // count # of triangles case 2: // Cohen: ntri = sum (sum ((L * U) .* A)) / 2 OK (GrB_Matrix_nrows (&n, A)) ; - OK (GrB_Matrix_new (&C, GrB_UINT32, n, n)) ; + OK (GrB_Matrix_new (&C, ctype, n, n)) ; // mxm: outer product method, with mask OK (GxB_Desc_set (d, GxB_AxB_METHOD, GxB_AxB_GUSTAVSON)) ; - OK (GrB_mxm (C, A, NULL, GxB_PLUS_TIMES_UINT32, L, U, d)) ; + OK (GrB_mxm (C, A, NULL, semiring, L, U, d)) ; t [0] = simple_toc (tic) ; simple_tic (tic) ; - OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GxB_PLUS_INT64_MONOID, + OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GrB_PLUS_MONOID_INT64, C, NULL)) ; ntri /= 2 ; break ; @@ -158,55 +161,55 @@ GrB_Info tricount // count # of triangles case 3: // Sandia: ntri = sum (sum ((L * L) .* L)) OK (GrB_Matrix_nrows (&n, L)) ; - OK (GrB_Matrix_new (&C, GrB_UINT32, n, n)) ; + OK (GrB_Matrix_new (&C, ctype, n, n)) ; OK (GxB_Desc_set (d, GxB_AxB_METHOD, GxB_AxB_GUSTAVSON)) ; - OK (GrB_mxm (C, L, NULL, GxB_PLUS_TIMES_UINT32, L, L, d)) ; + OK (GrB_mxm (C, L, NULL, semiring, L, L, d)) ; t [0] = simple_toc (tic) ; simple_tic (tic) ; - OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GxB_PLUS_INT64_MONOID, + OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GrB_PLUS_MONOID_INT64, C, NULL)) ; break ; case 4: // Sandia2: ntri = sum (sum ((U * U) .* U)) OK (GrB_Matrix_nrows (&n, U)) ; - OK (GrB_Matrix_new (&C, GrB_UINT32, n, n)) ; + OK (GrB_Matrix_new (&C, ctype, n, n)) ; // mxm: outer product method, with mask OK (GxB_Desc_set (d, GxB_AxB_METHOD, GxB_AxB_GUSTAVSON)) ; - OK (GrB_mxm (C, U, NULL, GxB_PLUS_TIMES_UINT32, U, U, d)) ; + OK (GrB_mxm (C, U, NULL, semiring, U, U, d)) ; t [0] = simple_toc (tic) ; simple_tic (tic) ; - OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GxB_PLUS_INT64_MONOID, + OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GrB_PLUS_MONOID_INT64, C, NULL)) ; break ; case 5: // SandiaDot: ntri = sum (sum ((L * U') .* L)) OK (GrB_Matrix_nrows (&n, U)) ; - OK (GrB_Matrix_new (&C, GrB_UINT32, n, n)) ; + OK (GrB_Matrix_new (&C, ctype, n, n)) ; OK (GrB_Descriptor_new (&d)) ; OK (GxB_Desc_set (d, GrB_INP1, GrB_TRAN)) ; // mxm: dot product method, with mask OK (GxB_Desc_set (d, GxB_AxB_METHOD, GxB_AxB_DOT)) ; - OK (GrB_mxm (C, L, NULL, GxB_PLUS_TIMES_UINT32, L, U, d)) ; + OK (GrB_mxm (C, L, NULL, semiring, L, U, d)) ; t [0] = simple_toc (tic) ; simple_tic (tic) ; - OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GxB_PLUS_INT64_MONOID, + OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GrB_PLUS_MONOID_INT64, C, NULL)) ; break ; case 6: // SandiaDot2: ntri = sum (sum ((U * L') .* U)) OK (GrB_Matrix_nrows (&n, U)) ; - OK (GrB_Matrix_new (&C, GrB_UINT32, n, n)) ; + OK (GrB_Matrix_new (&C, ctype, n, n)) ; OK (GrB_Descriptor_new (&d)) ; OK (GxB_Desc_set (d, GrB_INP1, GrB_TRAN)) ; // mxm: dot product method, with mask OK (GxB_Desc_set (d, GxB_AxB_METHOD, GxB_AxB_DOT)) ; - OK (GrB_mxm (C, U, NULL, GxB_PLUS_TIMES_UINT32, U, L, d)) ; + OK (GrB_mxm (C, U, NULL, semiring, U, L, d)) ; t [0] = simple_toc (tic) ; simple_tic (tic) ; - OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GxB_PLUS_INT64_MONOID, + OK (GrB_Matrix_reduce_INT64 (&ntri, NULL, GrB_PLUS_MONOID_INT64, C, NULL)) ; break ; diff --git a/Demo/Source/usercomplex.c b/Demo/Source/usercomplex.c index b670d1c811..2e9228d266 100644 --- a/Demo/Source/usercomplex.c +++ b/Demo/Source/usercomplex.c @@ -16,8 +16,10 @@ #pragma warning (disable: 58 167 144 161 177 181 186 188 589 593 869 981 1418 1419 1572 1599 2259 2282 2557 2547 3280 ) #elif defined __GNUC__ #pragma GCC diagnostic ignored "-Wunused-parameter" +#if !defined ( __cplusplus ) #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" #endif +#endif GrB_BinaryOp Complex_first = NULL, Complex_second = NULL, Complex_min = NULL, Complex_max = NULL, Complex_plus = NULL, Complex_minus = NULL, @@ -49,11 +51,9 @@ GrB_Type Complex = NULL ; GrB_Monoid Complex_plus_monoid = NULL, Complex_times_monoid = NULL ; GrB_Semiring Complex_plus_times = NULL ; -#if GxB_STDC_VERSION >= 201112L - -#define ONE CMPLX(1,0) -#define ZERO CMPLX(0,0) -#define C double complex +#define ONE GxB_CMPLX(1,0) +#define ZERO GxB_CMPLX(0,0) +#define C GxB_FC64_t #define X *x #define Y *y @@ -61,12 +61,13 @@ GrB_Semiring Complex_plus_times = NULL ; #define T ONE #define F ZERO -#define BOOL(X) (X != ZERO) +#define BOOL(X) (creal (X) != 0 || cimag (X) != 0) //------------------------------------------------------------------------------ // binary functions, z=f(x,y), where CxC -> C //------------------------------------------------------------------------------ +#if GxB_STDC_VERSION >= 201112L GB_PUBLIC void complex_first (C Z, const C X, const C Y) { Z = X ; } GB_PUBLIC void complex_second (C Z, const C X, const C Y) { Z = Y ; } GB_PUBLIC void complex_pair (C Z, const C X, const C Y) { Z = ONE ; } @@ -76,6 +77,7 @@ GB_PUBLIC void complex_rminus (C Z, const C X, const C Y) { Z = Y - X ; } GB_PUBLIC void complex_times (C Z, const C X, const C Y) { Z = X * Y ; } GB_PUBLIC void complex_div (C Z, const C X, const C Y) { Z = X / Y ; } GB_PUBLIC void complex_rdiv (C Z, const C X, const C Y) { Z = Y / X ; } +#endif GB_PUBLIC void complex_min (C Z, const C X, const C Y) @@ -141,20 +143,41 @@ void complex_max (C Z, const C X, const C Y) // inequality operators follow the MATLAB convention -#define R(x) creal(x) - +#if GxB_STDC_VERSION >= 201112L GB_PUBLIC -void complex_iseq (C Z, const C X, const C Y) { Z = (X == Y) ? T : F ; } +void complex_iseq (C Z, const C X, const C Y) +{ + Z = (creal (X) == creal (Y) && cimag (X) == cimag (Y)) ? T : F ; +} + GB_PUBLIC -void complex_isne (C Z, const C X, const C Y) { Z = (X != Y) ? T : F ; } +void complex_isne (C Z, const C X, const C Y) +{ + Z = (creal (X) != creal (Y) || cimag (X) != cimag (Y)) ? T : F ; +} +#endif + GB_PUBLIC -void complex_isgt (C Z, const C X, const C Y) { Z = (R(X) > R(Y)) ? T : F ; } +void complex_isgt (C Z, const C X, const C Y) +{ + Z = (creal (X) > creal (Y)) ? T : F ; +} + GB_PUBLIC -void complex_islt (C Z, const C X, const C Y) { Z = (R(X) < R(Y)) ? T : F ; } +void complex_islt (C Z, const C X, const C Y) +{ + Z = (creal (X) < creal (Y)) ? T : F ; +} GB_PUBLIC -void complex_isge (C Z, const C X, const C Y) { Z = (R(X) >= R(Y)) ? T : F ; } +void complex_isge (C Z, const C X, const C Y) +{ + Z = (creal (X) >= creal (Y)) ? T : F ; +} GB_PUBLIC -void complex_isle (C Z, const C X, const C Y) { Z = (R(X) <= R(Y)) ? T : F ; } +void complex_isle (C Z, const C X, const C Y) +{ + Z = (creal (X) <= creal (Y)) ? T : F ; +} //------------------------------------------------------------------------------ // binary boolean functions, z=f(x,y), where CxC -> C @@ -184,49 +207,83 @@ void complex_xor (C Z, const C X, const C Y) // inequality operators follow the MATLAB convention +#if GxB_STDC_VERSION >= 201112L GB_PUBLIC -void complex_eq (bool Z, const C X, const C Y) { Z = (X == Y) ; } +void complex_eq (bool Z, const C X, const C Y) +{ + Z = (creal (X) == creal (Y) && cimag (X) == cimag (Y)) ; +} + GB_PUBLIC -void complex_ne (bool Z, const C X, const C Y) { Z = (X != Y) ; } +void complex_ne (bool Z, const C X, const C Y) +{ + Z = (creal (X) != creal (Y) || cimag (X) != cimag (Y)) ; +} +#endif + GB_PUBLIC -void complex_gt (bool Z, const C X, const C Y) { Z = (R (X) > R (Y)) ;} +void complex_gt (bool Z, const C X, const C Y) +{ + Z = (creal (X) > creal (Y)) ; +} + GB_PUBLIC -void complex_lt (bool Z, const C X, const C Y) { Z = (R (X) < R (Y)) ;} +void complex_lt (bool Z, const C X, const C Y) +{ + Z = (creal (X) < creal (Y)) ; +} + GB_PUBLIC -void complex_ge (bool Z, const C X, const C Y) { Z = (R (X) >= R (Y)) ;} +void complex_ge (bool Z, const C X, const C Y) +{ + Z = (creal (X) >= creal (Y)) ; +} + GB_PUBLIC -void complex_le (bool Z, const C X, const C Y) { Z = (R (X) <= R (Y)) ;} +void complex_le (bool Z, const C X, const C Y) +{ + Z = (creal (X) <= creal (Y)) ; +} //------------------------------------------------------------------------------ // binary functions, z=f(x,y), where double x double -> complex //------------------------------------------------------------------------------ +#if GxB_STDC_VERSION >= 201112L GB_PUBLIC -void complex_complex (C Z, const double X, const double Y) { Z = CMPLX (X,Y) ; } +void complex_complex (C Z, const double X, const double Y) +{ + Z = GxB_CMPLX (X,Y) ; +} +#endif //------------------------------------------------------------------------------ // unary functions, z=f(x) where C -> C //------------------------------------------------------------------------------ +#if GxB_STDC_VERSION >= 201112L GB_PUBLIC -void complex_one (C Z, const C X) { Z = 1. ; } +void complex_one (C Z, const C X) { Z = ONE ; } GB_PUBLIC void complex_identity (C Z, const C X) { Z = X ; } GB_PUBLIC void complex_ainv (C Z, const C X) { Z = -X ; } GB_PUBLIC -void complex_abs (C Z, const C X) { Z = CMPLX (cabs (X), 0) ; } +void complex_minv (C Z, const C X) { Z = 1. / X ; } +GB_PUBLIC +void complex_conj (C Z, const C X) { Z = conj (X) ; } +#endif + GB_PUBLIC -void complex_minv (C Z, const C X) { Z = 1. / X ; } +void complex_abs (C Z, const C X) { Z = GxB_CMPLX (cabs (X), 0) ; } GB_PUBLIC void complex_not (C Z, const C X) { Z = BOOL (X) ? F : T ; } -GB_PUBLIC -void complex_conj (C Z, const C X) { Z = conj (X) ; } //------------------------------------------------------------------------------ // unary functions, z=f(x) where C -> double //------------------------------------------------------------------------------ +#if GxB_STDC_VERSION >= 201112L GB_PUBLIC void complex_real (double Z, const C X) { Z = creal (X) ; } GB_PUBLIC @@ -235,27 +292,16 @@ GB_PUBLIC void complex_cabs (double Z, const C X) { Z = cabs (X) ; } GB_PUBLIC void complex_angle (double Z, const C X) { Z = carg (X) ; } +#endif //------------------------------------------------------------------------------ // unary functions, z=f(x) where double -> C //------------------------------------------------------------------------------ GB_PUBLIC -void complex_complex_real (C Z, const double X) { Z = CMPLX (X, 0) ; } +void complex_complex_real (C Z, const double X) { Z = GxB_CMPLX (X, 0) ; } GB_PUBLIC -void complex_complex_imag (C Z, const double X) { Z = CMPLX (0, X) ; } - -#else - -//------------------------------------------------------------------------------ -// Pre-ANSI C11: just make to easier to write this file -//------------------------------------------------------------------------------ - -#define ONE 0 -#define ZERO 1 -#define C double - -#endif +void complex_complex_imag (C Z, const double X) { Z = GxB_CMPLX (0, X) ; } //------------------------------------------------------------------------------ // OK: check if a method fails @@ -274,122 +320,251 @@ void complex_complex_imag (C Z, const double X) { Z = CMPLX (0, X) ; } // Complex_init: create the complex type, operators, monoids, and semiring //------------------------------------------------------------------------------ +#undef C +#undef D +#define C Complex +#define D GrB_FP64 + +#define U (GxB_unary_function) +#define B (GxB_binary_function) + GB_PUBLIC -GrB_Info Complex_init ( ) +GrB_Info Complex_init (bool builtin_complex) { - //-------------------------------------------------------------------------- - // create the Complex type - //-------------------------------------------------------------------------- + GrB_Info info ; -#if GxB_STDC_VERSION >= 201112L +#if GxB_STDC_VERSION < 201112L + // the Complex type requires the ANSI C11 "double complex" type + builtin_complex = true ; +#endif - GrB_Info info ; - OK (GrB_Type_new (&Complex, sizeof (C))) ; + //-------------------------------------------------------------------------- + // create the Complex type, or set to GxB_FC64 + //-------------------------------------------------------------------------- - #undef C - #undef D - #define C Complex - #define D GrB_FP64 + if (builtin_complex) + { + // use the built-in type + Complex = GxB_FC64 ; + } + else + { + // create the user-defined type + #if GxB_STDC_VERSION >= 201112L + OK (GrB_Type_new (&Complex, sizeof (GxB_FC64_t))) ; + #endif + } //-------------------------------------------------------------------------- // create the Complex binary operators, CxC->C //-------------------------------------------------------------------------- - OK (GrB_BinaryOp_new (&Complex_first , complex_first , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_second , complex_second , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_pair , complex_pair , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_min , complex_min , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_max , complex_max , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_plus , complex_plus , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_minus , complex_minus , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_rminus , complex_rminus , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_times , complex_times , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_div , complex_div , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_rdiv , complex_rdiv , C, C, C)) ; + if (builtin_complex) + { + // use the built-in versions + Complex_first = GxB_FIRST_FC64 ; + Complex_second = GxB_SECOND_FC64 ; + Complex_pair = GxB_PAIR_FC64 ; + Complex_plus = GxB_PLUS_FC64 ; + Complex_minus = GxB_MINUS_FC64 ; + Complex_rminus = GxB_RMINUS_FC64 ; + Complex_times = GxB_TIMES_FC64 ; + Complex_div = GxB_DIV_FC64 ; + Complex_rdiv = GxB_RDIV_FC64 ; + } + else + { + // create user-defined versions + #if GxB_STDC_VERSION >= 201112L + OK (GrB_BinaryOp_new (&Complex_first , B complex_first , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_second , B complex_second , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_pair , B complex_pair , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_plus , B complex_plus , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_minus , B complex_minus , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_rminus , B complex_rminus , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_times , B complex_times , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_div , B complex_div , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_rdiv , B complex_rdiv , C, C, C)) ; + #endif + } + + // these are not built-in + OK (GrB_BinaryOp_new (&Complex_min , B complex_min , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_max , B complex_max , C, C, C)) ; //-------------------------------------------------------------------------- // create the Complex binary comparison operators, CxC -> C //-------------------------------------------------------------------------- - OK (GrB_BinaryOp_new (&Complex_iseq , complex_iseq , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_isne , complex_isne , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_isgt , complex_isgt , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_islt , complex_islt , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_isge , complex_isge , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_isle , complex_isle , C, C, C)) ; + if (builtin_complex) + { + // use the built-in versions + Complex_iseq = GxB_ISEQ_FC64 ; + Complex_isne = GxB_ISNE_FC64 ; + } + else + { + // create user-defined versions + #if GxB_STDC_VERSION >= 201112L + OK (GrB_BinaryOp_new (&Complex_iseq , B complex_iseq , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_isne , B complex_isne , C, C, C)) ; + #endif + } + + // these are not built-in + OK (GrB_BinaryOp_new (&Complex_isgt , B complex_isgt , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_islt , B complex_islt , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_isge , B complex_isge , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_isle , B complex_isle , C, C, C)) ; //-------------------------------------------------------------------------- // create the Complex boolean operators, CxC -> C //-------------------------------------------------------------------------- - OK (GrB_BinaryOp_new (&Complex_or , complex_or , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_and , complex_and , C, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_xor , complex_xor , C, C, C)) ; + // these are not built-in + OK (GrB_BinaryOp_new (&Complex_or , B complex_or , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_and , B complex_and , C, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_xor , B complex_xor , C, C, C)) ; //-------------------------------------------------------------------------- // create the Complex binary operators, CxC -> bool //-------------------------------------------------------------------------- - OK (GrB_BinaryOp_new (&Complex_eq , complex_eq , GrB_BOOL, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_ne , complex_ne , GrB_BOOL, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_gt , complex_gt , GrB_BOOL, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_lt , complex_lt , GrB_BOOL, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_ge , complex_ge , GrB_BOOL, C, C)) ; - OK (GrB_BinaryOp_new (&Complex_le , complex_le , GrB_BOOL, C, C)) ; + if (builtin_complex) + { + // use the built-in versions + Complex_eq = GxB_EQ_FC64 ; + Complex_ne = GxB_NE_FC64 ; + } + else + { + // create user-defined versions + #if GxB_STDC_VERSION >= 201112L + OK (GrB_BinaryOp_new (&Complex_eq , B complex_eq , GrB_BOOL, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_ne , B complex_ne , GrB_BOOL, C, C)) ; + #endif + } + + // these are not built-in + OK (GrB_BinaryOp_new (&Complex_gt , B complex_gt , GrB_BOOL, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_lt , B complex_lt , GrB_BOOL, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_ge , B complex_ge , GrB_BOOL, C, C)) ; + OK (GrB_BinaryOp_new (&Complex_le , B complex_le , GrB_BOOL, C, C)) ; //-------------------------------------------------------------------------- // create the Complex binary operator, double x double -> C //-------------------------------------------------------------------------- - OK (GrB_BinaryOp_new (&Complex_complex, complex_complex, C, D, D)) ; + if (builtin_complex) + { + // use the built-in versions + Complex_complex = GxB_CMPLX_FP64 ; + } + else + { + // create user-defined versions + #if GxB_STDC_VERSION >= 201112L + OK (GrB_BinaryOp_new (&Complex_complex, B complex_complex, C, D, D)) ; + #endif + } //-------------------------------------------------------------------------- // create the Complex unary operators, C->C //-------------------------------------------------------------------------- - OK (GrB_UnaryOp_new (&Complex_one , complex_one , C, C)) ; - OK (GrB_UnaryOp_new (&Complex_identity, complex_identity, C, C)) ; - OK (GrB_UnaryOp_new (&Complex_ainv , complex_ainv , C, C)) ; - OK (GrB_UnaryOp_new (&Complex_abs , complex_abs , C, C)) ; - OK (GrB_UnaryOp_new (&Complex_minv , complex_minv , C, C)) ; - OK (GrB_UnaryOp_new (&Complex_not , complex_not , C, C)) ; - OK (GrB_UnaryOp_new (&Complex_conj , complex_conj , C, C)) ; + if (builtin_complex) + { + // use the built-in versions + Complex_one = GxB_ONE_FC64 ; + Complex_identity = GxB_IDENTITY_FC64 ; + Complex_ainv = GxB_AINV_FC64 ; + Complex_minv = GxB_MINV_FC64 ; + Complex_conj = GxB_CONJ_FC64 ; + } + else + { + // create user-defined versions + #if GxB_STDC_VERSION >= 201112L + OK (GrB_UnaryOp_new (&Complex_one , U complex_one , C, C)) ; + OK (GrB_UnaryOp_new (&Complex_identity, U complex_identity, C, C)) ; + OK (GrB_UnaryOp_new (&Complex_ainv , U complex_ainv , C, C)) ; + OK (GrB_UnaryOp_new (&Complex_minv , U complex_minv , C, C)) ; + OK (GrB_UnaryOp_new (&Complex_conj , U complex_conj , C, C)) ; + #endif + } + + // these are not built-in + OK (GrB_UnaryOp_new (&Complex_abs , U complex_abs , C, C)) ; + OK (GrB_UnaryOp_new (&Complex_not , U complex_not , C, C)) ; //-------------------------------------------------------------------------- // create the unary functions, C -> double //-------------------------------------------------------------------------- - OK (GrB_UnaryOp_new (&Complex_real , complex_real , D, C)) ; - OK (GrB_UnaryOp_new (&Complex_imag , complex_imag , D, C)) ; - OK (GrB_UnaryOp_new (&Complex_cabs , complex_cabs , D, C)) ; - OK (GrB_UnaryOp_new (&Complex_angle , complex_angle , D, C)) ; + if (builtin_complex) + { + // use the built-in versions + Complex_real = GxB_CREAL_FC64 ; + Complex_imag = GxB_CIMAG_FC64 ; + Complex_cabs = GxB_ABS_FC64 ; + Complex_angle = GxB_CARG_FC64 ; + } + else + { + // create user-defined versions + #if GxB_STDC_VERSION >= 201112L + OK (GrB_UnaryOp_new (&Complex_real , U complex_real , D, C)) ; + OK (GrB_UnaryOp_new (&Complex_imag , U complex_imag , D, C)) ; + OK (GrB_UnaryOp_new (&Complex_cabs , U complex_cabs , D, C)) ; + OK (GrB_UnaryOp_new (&Complex_angle , U complex_angle , D, C)) ; + #endif + } //-------------------------------------------------------------------------- // create the unary functions, double -> C //-------------------------------------------------------------------------- - OK (GrB_UnaryOp_new (&Complex_complex_real , complex_complex_real , C, D)) ; - OK (GrB_UnaryOp_new (&Complex_complex_imag , complex_complex_imag , C, D)) ; + // these are not built-in + OK (GrB_UnaryOp_new (&Complex_complex_real, U complex_complex_real, C, D)) ; + OK (GrB_UnaryOp_new (&Complex_complex_imag, U complex_complex_imag, C, D)) ; //-------------------------------------------------------------------------- // create the Complex monoids //-------------------------------------------------------------------------- - double complex Complex_1 = ONE ; - double complex Complex_0 = ZERO ; - - OK (GrB_Monoid_new_UDT (&Complex_plus_monoid, Complex_plus, &Complex_0)) ; - OK (GrB_Monoid_new_UDT (&Complex_times_monoid, Complex_times, &Complex_1)) ; + if (builtin_complex) + { + // use the built-in versions + Complex_plus_monoid = GxB_PLUS_FC64_MONOID ; + Complex_times_monoid = GxB_TIMES_FC64_MONOID ; + } + else + { + // create user-defined versions + #if GxB_STDC_VERSION >= 201112L + double complex C_1 = ONE ; + double complex C_0 = ZERO ; + OK (GrB_Monoid_new_UDT (&Complex_plus_monoid, Complex_plus, &C_0)) ; + OK (GrB_Monoid_new_UDT (&Complex_times_monoid, Complex_times, &C_1)) ; + #endif + } - //-------------------------------------------------------------------------- + //---------------------------------------------------------------------- // create the Complex plus-times semiring - //-------------------------------------------------------------------------- + //---------------------------------------------------------------------- - // more could be created, but this suffices for testing GraphBLAS - OK (GrB_Semiring_new - (&Complex_plus_times, Complex_plus_monoid, Complex_times)) ; -#endif + if (builtin_complex) + { + // use the built-in versions + Complex_plus_times = GxB_PLUS_TIMES_FC64 ; + } + else + { + // more could be created, but this suffices for testing GraphBLAS + OK (GrB_Semiring_new (&Complex_plus_times, Complex_plus_monoid, + Complex_times)) ; + } return (GrB_SUCCESS) ; } @@ -399,12 +574,13 @@ GrB_Info Complex_init ( ) // Complex_finalize: free all complex types, operators, monoids, and semiring //------------------------------------------------------------------------------ +// These may be built-in types and operators. They are safe to free; the +// GrB_*_free functions silently do nothing if asked to free bulit-in objects. + GB_PUBLIC GrB_Info Complex_finalize ( ) { -#if GxB_STDC_VERSION >= 201112L - //-------------------------------------------------------------------------- // free the Complex plus-times semiring //-------------------------------------------------------------------------- @@ -495,7 +671,6 @@ GrB_Info Complex_finalize ( ) //-------------------------------------------------------------------------- GrB_Type_free (&Complex) ; -#endif return (GrB_SUCCESS) ; } diff --git a/Demo/Source/wathen.c b/Demo/Source/wathen.c index 2e21369cb2..3b7ebf9323 100644 --- a/Demo/Source/wathen.c +++ b/Demo/Source/wathen.c @@ -103,7 +103,7 @@ GrB_Info wathen // construct a random Wathen matrix if (rho_given == NULL) { // compute a random RHO matrix - rho_rand = malloc (nx * ny * sizeof (double)) ; + rho_rand = (double *) malloc (nx * ny * sizeof (double)) ; if (rho_rand == NULL) { // out of memory FREE_ALL ; @@ -154,9 +154,9 @@ GrB_Info wathen // construct a random Wathen matrix // allocate the tuples int64_t ntriplets = nx*ny*64 ; - I = malloc (ntriplets * sizeof (int64_t)) ; - J = malloc (ntriplets * sizeof (int64_t)) ; - X = malloc (ntriplets * sizeof (double )) ; + I = (GrB_Index *) malloc (ntriplets * sizeof (GrB_Index)) ; + J = (GrB_Index *) malloc (ntriplets * sizeof (GrB_Index)) ; + X = (double *) malloc (ntriplets * sizeof (double )) ; if (I == NULL || J == NULL || X == NULL) { // out of memory FREE_ALL ; @@ -329,7 +329,8 @@ GrB_Info wathen // construct a random Wathen matrix } // create a unary operator to scale by RHO(i,j) - OK (GrB_UnaryOp_new (&rho_op, rho_scale, GrB_FP64, GrB_FP64)) ; + OK (GrB_UnaryOp_new (&rho_op, + (GxB_unary_function) rho_scale, GrB_FP64, GrB_FP64)) ; for (int j = 1 ; j <= ny ; j++) { diff --git a/Demo/demo b/Demo/demo index e4b266324b..07aac1ccf8 100755 --- a/Demo/demo +++ b/Demo/demo @@ -2,6 +2,7 @@ ../build/wildtype_demo > wildtype_demo.out ../build/simple_demo > simple_demo.out ../build/complex_demo > complex_demo_out.m +../build/complex_demo 1 > complex_demo_out2.m ../build/pthread_demo > pthread_demo.out ../build/openmp_demo > openmp_demo.out diff --git a/Doc/ChangeLog b/Doc/ChangeLog index ef7d2a7011..8065ff1af4 100644 --- a/Doc/ChangeLog +++ b/Doc/ChangeLog @@ -1,3 +1,37 @@ +Version 4.0.0, FUTURE, 2020 (this list is tentative): + + * GrB_wait(), with no inputs: will be removed + * GrB_wait(&object): polymorphic function will be added + * GrB_*_nvals: will no longer guarantee completion; use GrB_wait(&object) + or non-polymorphic GrB_*_wait (&object) instead + * GrB_error: will have two inputs: a string (char **) and an object + * V4.0.0 will otherwise be identical to V3.3.0. + +Version 3.3.0, June 26, 2020 + + * GrB_wait( ): with no input arguments, has been deprecated. It will + be removed in V4.0. + * added complex types: GxB_FC32 and GxB_FC64, many unary operators, + binary operators, monoids, and semirings + * added GrB_*_apply_BinaryOp1st and 2nd: also GxB version with GxB_Scalar + * added bitwise operators: and their monoids and semirings + * added predefined GrB* monoids and semirings: from the v1.3 spec. + * MATLAB interface: added complex matrices and operators, bitwise + operators; improved performance + * changed typecasting rules: for casting floating point types to integers + * added GrB_*_wait: wait for specific object to complete + * added GrB_*_resize: same as prior GxB_*_resize functions + * added GrB_kronecker: same as prior GxB_kron + * added version methods: GrB_getVersion, GRB_VERSION, GRB_SUBVERSION + * added GrB_*_removeElement + * (18) bug fix: fixed typecasting in GB_dense_subassign_23, generic case + * (17) bug fix: non-polymorphic GrB_eWiseAdd and eWiseMult functions + were misnamed. + * DRAFT interfaces: A few functions have been added to use CUDA and the + Intel MKL library. These are visible in GraphBLAS.h but are + undocumented; do *not* use them yet. They will likely change without + warning, and without change the SuiteSparse:GraphBLAS version number. + Version 3.2.2, Apr 2, 2020 * (16) bug fix to MATLAB interface: for matrices with dimension > 2^53. @@ -89,7 +123,7 @@ Version 3.1.0, Oct 2, 2019 * (12) bug fix to GB_accum_mask: when C+=T if C has no entries except pending tuples * (11) bug fix to GB_resize: when pending tuples exist and vdim is growing - from vdim <= 1 to vdim > 1, GB_WAIT(A) is required first. + from vdim <= 1 to vdim > 1, matrix must be finished first. * (10) bug fix to GB_subref_phase1: "int nI" parameter should be int64_t. Version 3.0.1, July 26, 2019 @@ -173,7 +207,7 @@ Version 2.3.0 (BETA1), Feb 16, 2019 * added isequal function to Demos/ * added import/export method * added nthreads: to descriptor, the matrix, and a global nthreads - for GrB_wait, and added Context as parameter in many internal + setting, and added Context as parameter in many internal functions, to pass in Context->nthreads for future parallelism * defined all enum constants explicitly: no change to their values, this just ensures they remain fixed in future versions diff --git a/Doc/GraphBLAS_API_C.pdf b/Doc/GraphBLAS_API_C.pdf deleted file mode 100644 index aa265d7612..0000000000 Binary files a/Doc/GraphBLAS_API_C.pdf and /dev/null differ diff --git a/Doc/GraphBLAS_API_version.tex b/Doc/GraphBLAS_API_version.tex index 40289c79eb..5d954e8cd9 100644 --- a/Doc/GraphBLAS_API_version.tex +++ b/Doc/GraphBLAS_API_version.tex @@ -1,3 +1,3 @@ % GraphBLAS C API Specification version, at graphblas.org -1.2.0 -(May 18, 2018)% +1.3.0 +(Sept 25, 2019)% diff --git a/Doc/GraphBLAS_UserGuide.pdf b/Doc/GraphBLAS_UserGuide.pdf index 3341fa5fa4..9298cbade6 100644 Binary files a/Doc/GraphBLAS_UserGuide.pdf and b/Doc/GraphBLAS_UserGuide.pdf differ diff --git a/Doc/GraphBLAS_UserGuide.tex b/Doc/GraphBLAS_UserGuide.tex index edd3837e4f..16c7e997c2 100644 --- a/Doc/GraphBLAS_UserGuide.tex +++ b/Doc/GraphBLAS_UserGuide.tex @@ -15,6 +15,21 @@ \hyphenation{Graph-BLAS} \hyphenation{Suite-Sparse-Graph-BLAS} +\DeclareMathOperator{\sech}{sech} +\DeclareMathOperator{\csch}{csch} +\DeclareMathOperator{\arcsec}{arcsec} +\DeclareMathOperator{\arccot}{arcCot} +\DeclareMathOperator{\arccsc}{arcCsc} +\DeclareMathOperator{\arccosh}{arcCosh} +\DeclareMathOperator{\arcsinh}{arcsinh} +\DeclareMathOperator{\arctanh}{arctanh} +\DeclareMathOperator{\arcsech}{arcsech} +\DeclareMathOperator{\arccsch}{arcCsch} +\DeclareMathOperator{\arccoth}{arcCoth} +\DeclareMathOperator{\sgn}{sgn} +\DeclareMathOperator{\erf}{erf} +\DeclareMathOperator{\erfc}{erfc} + \newenvironment{packed_itemize}{ \begin{itemize} \setlength{\itemsep}{1pt} @@ -28,7 +43,7 @@ \small davis@tamu.edu, Texas A\&M University. \\ \small -http://www.suitesparse.com and http://aldenmath.com +http://suitesparse.com and http://aldenmath.com } % version and date are set by cmake (see GraphBLAS/CMakeLists.txt) @@ -88,11 +103,18 @@ \section{Introduction} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Jos\'e Moreira, and Carl Yang} \cite{BulucMattsonMcMillanMoreiraYang17,spec}, based on {\em GraphBLAS Mathematics} by Jeremy Kepner \cite{Kepner2017}. The GraphBLAS C API Specification is available at \url{http://graphblas.org}. This -version of SuiteSparse:GraphBLAS fully conforms to Version -\input{GraphBLAS_API_version.tex} of that specification. In this User Guide, -aspects of the GraphBLAS specification that would be true for any GraphBLAS -implementation are simply called ``GraphBLAS.'' Details unique to this -particular implementation are referred to as SuiteSparse:GraphBLAS. +version of SuiteSparse:GraphBLAS conforms to Version +\input{GraphBLAS_API_version.tex} +of {\em The GraphBLAS C API specification}, with one exception: +% TODO in 4.0: Remove when GrB_wait() is removed: +the single-input polymorphic function \verb'GrB_wait(&object)' does not appear +in this version, since it conflicts with the no-input \verb'GrB_wait()'. Use +the non-polymorphic versions instead (\verb'GrB_Matrix_wait(&C)' for example). + +In this User Guide, aspects of the GraphBLAS specification that would be true +for any GraphBLAS implementation are simply called ``GraphBLAS.'' Details +unique to this particular implementation are referred to as +SuiteSparse:GraphBLAS. \begin{spec} {\bf SPEC:} See the tag {\bf SPEC:} for SuiteSparse extensions to the spec. @@ -101,10 +123,50 @@ \section{Introduction} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \end{spec} \newpage -\subsection{Release Notes:} +\subsection{Future plans:} + +\begin{itemize} + +\item Version 4.0.0 (likely in July, 2020), will follow the V2.0 of the C API. + The following changes are tentative, and depend on the final release of the + V2.0 C API. + + % TODO in 4.0: revise this as needed: + \verb'GrB_wait()', with no inputs: will be removed. + \verb'GrB_wait(&object)': polymorphic function will be added. + \verb'GrB_*_nvals' and related functions: + will no longer guarantee completion + (per the v1.3 C API); + use \verb'GrB_wait(&object)' + or non-polymorphic \verb'GrB_*_wait(&object)' instead. + \verb'GrB_error' will change; it will take two parameters, + \verb'GrB_error(&s,C)' where \verb's' is the error string generated + when \verb'C' was last operated on. + V4.0 will otherwise be identical to V3.3.0. +\end{itemize} + +\subsection{Release Notes:} \begin{itemize} +\item Version 3.3.0 (June 26, 2020). Compliant with V1.3 of the C API + (except that the polymorphic \verb'GrB_wait(&object)' doesn't appear yet; + it will appear in V4.0). + + Added complex types (\verb'GxB_FC32' and \verb'GxB_FC64'), many unary + operators, binary operators, monoids, and semirings. Added bitwise + operators, and their monoids and semirings. Added the predefined monoids + and semirings from the v1.3 spec. MATLAB interface: added complex matrices + and operators, and changed behavior of integer operations to more closely + match the behavior on MATLAB integer matrices. The rules for typecasting + large floating point values to integers has changed. The specific + object-based \verb'GrB_Matrix_wait', \verb'GrB_Vector_wait', etc, functions + have been added. The no-argument \verb'GrB_wait()' is deprecated. Added + \verb'GrB_getVersion', \verb'GrB_Matrix_resize', \verb'GrB_Vector_resize', + \verb'GrB_kronecker', \verb'GrB_*_wait', scalar binding with binary + operators for \verb'GrB_apply', \verb'GrB_Matrix_removeElement', and + \verb'GrB_Vector_removeElement'. + \item Version 3.2.0 (Feb 20, 2020). Faster \verb'GrB_mxm', \verb'GrB_mxv', and \verb'GrB_vxm', and faster operations on dense matrices/vectors. Removed compile-time user objects (\verb'GxB_*_define'), since these were not @@ -166,8 +228,8 @@ \subsection{Release Notes:} \item Version 2.2 (Nov 2018) adds user-defined objects at compile-time, via user \verb'*.m4' files placed in -\verb'GraphBLAS/User', which use the \verb'GxB_*_define' macros described in -Section~\ref{precompile} (NOTE: feature removed in v3.2). +\verb'GraphBLAS/User', which use the \verb'GxB_*_define' macros +(NOTE: feature removed in v3.2). The default matrix format is now \verb'GxB_BY_ROW'. % If you want the default format to be by column (the default in Version 2.1 and % earlier), just compile with \verb'-DBYCOL', or add \newline @@ -327,12 +389,12 @@ \subsection{Overview of GraphBLAS methods and operations} %===================== brief overview, the full scope of GraphBLAS extensions of these operations can now be described. -GraphBLAS has 11 built-in scalar types: Boolean, single and double precision -floating-point, and 8, 16, 32, and 64-bit signed and unsigned integers. In -addition, user-defined scalar types can be created from nearly any C -\verb'typedef', as long as the entire type fits in a fixed-size contiguous -block of memory (of arbitrary size). All of these types can be used to create -GraphBLAS sparse matrices, vectors, or scalars. +GraphBLAS has 13 built-in scalar types: Boolean, single and double precision +floating-point (real and complex), and 8, 16, 32, and 64-bit signed and +unsigned integers. In addition, user-defined scalar types can be created from +nearly any C \verb'typedef', as long as the entire type fits in a fixed-size +contiguous block of memory (of arbitrary size). All of these types can be used +to create GraphBLAS sparse matrices, vectors, or scalars. The scalar addition of conventional matrix multiplication is replaced with a {\em monoid}. A monoid is an associative and commutative binary operator @@ -341,11 +403,13 @@ \subsection{Overview of GraphBLAS methods and operations} %===================== such that \verb'f(x,id)=f(id,x)=x'. Performing matrix multiplication with a semiring uses a monoid in place of the ``add'' operator, scalar addition being just one of many possible monoids. The identity value of addition is zero, -since $x+0=0+x=x$. GraphBLAS includes eight built-in operators suitable for +since $x+0=0+x=x$. GraphBLAS includes many built-in operators suitable for use as a monoid: min (with an identity value of positive infinity), max (whose -identity is negative infinity), add (identity is zero) multiply (with an -identity of one), and four logical operators: AND, OR, exclusive-OR, and -Boolean equality. User-created monoids can be defined with any associative and +identity is negative infinity), add (identity is zero), multiply (with an +identity of one), four logical operators: AND, OR, exclusive-OR, and +Boolean equality (XNOR), four bitwise operators (AND, OR, XOR, and XNOR), +and the ANY operator. +User-created monoids can be defined with any associative and commutative operator that has an identity value. Finally, a semiring can use any built-in or user-defined binary operator @@ -355,25 +419,21 @@ \subsection{Overview of GraphBLAS methods and operations} %===================== and multiply operators, as long these few rules are followed. Just considering built-in types and operators, GraphBLAS can perform -\verb'C=A*B' in 1355 unique semirings. With typecasting, any of these 1355 -semirings can be applied to matrices \verb'C', \verb'A', and \verb'B' of any of -the 11 types, in any combination. This gives $1355 \times 11^3 = 1,803,505$ -possible kinds of sparse matrix multiplication supported by GraphBLAS, and this -is counting just built-in types and operators. By contrast, MATLAB provides -just two semirings for its sparse matrix multiplication \verb'C=A*B': +\verb'C=A*B' in 2,438 unique semirings. With typecasting, any of these 2,438 +semirings can be applied to matrices \verb'C', \verb'A', and \verb'B' +of 13 predefined types, in any combination. This gives over 5 million possible +kinds of sparse matrix multiplication supported by GraphBLAS, and this is +counting just built-in types and operators. By contrast, MATLAB provides just +two semirings for its sparse matrix multiplication \verb'C=A*B': plus-times-double and plus-times-complex, not counting the typecasting that -MATLAB does when multiplying a real matrix times a complex matrix. All of the -1.4 million forms of matrix multiplication methods in SuiteSparse:GraphBLAS are -typically just as fast as computing \verb'C=A*B' in MATLAB using its own native -sparse matrix multiplication methods, and often faster when parallelism can -be effectively used. +MATLAB does when multiplying a real matrix times a complex matrix. A monoid can also be used in a reduction operation, like \verb's=sum(A)' in MATLAB. MATLAB provides the plus, times, min, and max reductions of a real or complex sparse matrix as \verb's=sum(A)', \verb's=prod(A)', \verb's=min(A)', and \verb's=max(A)', respectively. In GraphBLAS, any monoid can be used (min, -max, plus, times, AND, OR, exclusive-OR, equality, or any user-defined monoid, -on any user-defined type). +max, plus, times, AND, OR, exclusive-OR, equality, bitwise operators, +or any user-defined monoid on any user-defined type). Element-wise operations are also expanded from what can be done in MATLAB. Consider matrix addition, \verb'C=A+B' in MATLAB. The pattern of the result is @@ -630,7 +690,8 @@ \subsection{The accumulator and the mask} %===================================== ${\bf Z=C\odot T}$, and \verb'GB_spec_mask.m', which computes ${\bf C \langle M \rangle = Z}$. SuiteSparse:GraphBLAS includes a complete list of \verb'GB_spec_*' functions that illustrate every GraphBLAS operation; -these are discussed in in Section~\ref{spec}. +these are discussed in the \verb'GraphBLAS_Test.pdf' document in +the \verb'GraphBLAS/Test' folder. The methods in Figure~\ref{fig_accummask} rely heavily on MATLAB's logical matrix indexing. For those unfamiliar with logical indexing in MATLAB, here is @@ -660,9 +721,9 @@ \subsection{The accumulator and the mask} %===================================== 4 -14 -15 1 \end{verbatim} } \end{mdframed} In MATLAB, logical indexing with a sparse matrix \verb'A' and sparse logical -matrix \verb'Mask' is very efficient since MATLAB supports sparse logical -matrices. The Mask operator in GraphBLAS works identically as sparse logical -indexing in MATLAB, and is equally as fast (or faster) in SuiteSparse:GraphBLAS. +matrix \verb'Mask' is a built-in method. The Mask operator in GraphBLAS works +identically as sparse logical indexing in MATLAB, but is typically far faster +in SuiteSparse:GraphBLAS than the same operation using MATLAB sparse matrices. %=============================================================================== \subsection{Typecasting} %====================================================== @@ -683,20 +744,24 @@ \subsection{Typecasting} %====================================================== error code, \verb'GrB_DOMAIN_MISMATCH' (refer to Section~\ref{error} for a complete list of error codes). Typecasting can only be done between built-in types, and it follows the rules of the ANSI C language (not MATLAB) wherever -the rules of ANSI C are well-defined. In particular, a large integer outside -the range of a smaller one is wrapped, modulo style. This differs from MATLAB. - -However, unlike MATLAB, the C language specification states that the results of -typecasting a \verb'float' or \verb'double' to an integer type is not always -defined. In SuiteSparse:GraphBLAS, whenever C leaves the result undefined the -rules used in MATLAB are followed. In particular \verb'+Inf' converts to the -largest integer value, \verb'-Inf' converts to the smallest (zero for unsigned -integers), and \verb'NaN' converts to zero. Other than these special cases, -SuiteSparse:GraphBLAS trusts the C compiler for the rest of its typecasting. +the rules of ANSI C are well-defined. + +However, unlike MATLAB, the ANSI C11 language specification states that the +results of typecasting a \verb'float' or \verb'double' to an integer type is +not always defined. In SuiteSparse:GraphBLAS, whenever C leaves the result +undefined the rules used in MATLAB are followed. In particular \verb'+Inf' +converts to the largest integer value, \verb'-Inf' converts to the smallest +(zero for unsigned integers), and \verb'NaN' converts to zero. Positive values +outside the range of the integer are converted to the largest positive integer, +and negative values less than the most negative integer are converted to that +most negative integer. Other than these special cases, SuiteSparse:GraphBLAS +trusts the C compiler for the rest of its typecasting. Typecasting to \verb'bool' is fully defined in the C language specification, even for \verb'NaN'. The result is \verb'false' if the value compares equal to -zero, and true otherwise. Thus \verb'NaN' converts to \verb'true'. +zero, and true otherwise. Thus \verb'NaN' converts to \verb'true'. This is +unlike MATLAB, which does not allow a typecast of a \verb'NaN' to the MATLAB +logical type. \begin{spec} {\bf SPEC:} the GraphBLAS API states that typecasting follows the rules of ANSI @@ -741,6 +806,10 @@ \subsection{Notation and list of GraphBLAS operations} %======================== \hline \verb'GrB_apply' & apply unary operator & ${\bf C \langle M \rangle = C \odot} f{\bf (A)}$ \\ & & ${\bf w \langle m \rangle = w \odot} f{\bf (u)}$ \\ + & apply binary operator & ${\bf C \langle M \rangle = C \odot} f({\bf A},y)$ \\ + & & ${\bf C \langle M \rangle = C \odot} f(x,{\bf A})$ \\ + & & ${\bf w \langle m \rangle = w \odot} f({\bf u},y)$ \\ + & & ${\bf w \langle m \rangle = w \odot} f(x,{\bf u})$ \\ \hline \verb'GxB_select' & apply select operator & ${\bf C \langle M \rangle = C \odot} f({\bf A},k)$ \\ & & ${\bf w \langle m \rangle = w \odot} f({\bf u},k)$ \\ @@ -750,11 +819,11 @@ \subsection{Notation and list of GraphBLAS operations} %======================== \hline \verb'GrB_transpose' & transpose & ${\bf C \langle M \rangle = C \odot A^{\sf T}}$ \\ \hline -\verb'GxB_kron' & Kronecker product & ${\bf C \langle M \rangle = C \odot \mbox{kron}(A, B)}$ \\ +\verb'GrB_kronecker' & Kronecker product & ${\bf C \langle M \rangle = C \odot \mbox{kron}(A, B)}$ \\ \hline \end{tabular} } -\vspace{0.05in} +\vspace{0.15in} Each operation takes an optional \verb'GrB_Descriptor' argument that modifies the operation. The input matrices ${\bf A}$ and ${\bf B}$ can be optionally @@ -776,7 +845,7 @@ \subsection{Notation and list of GraphBLAS operations} %======================== \newpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Interfaces to MATLAB, Python, and Julia} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Interfaces to MATLAB, Python, Julia, Java} %%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% The MATLAB interface to SuiteSparse:GraphBLAS is included with this @@ -796,17 +865,13 @@ \subsection{MATLAB Interface} the \verb'README.md' file in that directory. An easy-to-read output of the MATLAB demos can be found in \verb'GraphBLAS/GraphBLAS/demo/html'. -Prior to using an \verb'GrB' object or method, you must first call -\verb'GrB.init'. The best place to put this is in your MATLAB \verb'startup.m' -file, normally located in the user \verb'Documents/MATLAB' folder. - The MATLAB interface adds the \verb'GrB' class, which is an opaque MATLAB -object that contains a GraphBLAS matrix, either double or single precision, -boolean, or any of the built-in integer types. Complex matrix support will be -added in the future. MATLAB sparse and full matrices can be arbitrarily -mixed with GraphBLAS matrices. The following overloaded operators and methods -all work as you would expect for any matrix. The matrix multiplication -\verb'A*B' uses the conventional \verb'PLUS_TIMES' semiring. +object that contains a GraphBLAS matrix, either double or single precision +(real or complex), boolean, or any of the built-in integer types. MATLAB +sparse and full matrices can be arbitrarily mixed with GraphBLAS matrices. The +following overloaded operators and methods all work as you would expect for any +matrix. The matrix multiplication \verb'A*B' uses the conventional +\verb'PLUS_TIMES' semiring. {\footnotesize \begin{verbatim} @@ -814,54 +879,8 @@ \subsection{MATLAB Interface} -A +A ~A A' A.' A&B A|B b\A C(I,J)=A A~=B A>B A==B A<=B A>=B Awhatever'. This content is opaque -% to end user applications and can change without notice in future versions of -% this package. These names and content are technically visible to end-user -% applications, but this is only to enable the creation and use of polymorphic -% functions via the \verb'_Generic' keyword in ANSI C11. - \begin{spec} {\bf SPEC:} The following macros are extensions to the spec. \end{spec} @@ -1054,9 +1074,8 @@ \section{GraphBLAS Context and Sequence} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% GraphBLAS function & purpose & Section \\ \hline \verb'GrB_init' & start up GraphBLAS & \ref{init} \\ -\verb'GxB_init' & start up GraphBLAS with different \verb'malloc' - & \ref{xinit} \\ -\verb'GrB_wait' & force completion of pending operations & \ref{wait}\\ +\verb'GrB_getVersion'& C API supported by the library & \ref{getVersion} \\ +\verb'GxB_init' & start up GraphBLAS with different \verb'malloc' & \ref{xinit} \\ \verb'GrB_Info' & status code returned by GraphBLAS functions & \ref{info} \\ \verb'GrB_error' & get more details on the last error & \ref{error} \\ \verb'GrB_finalize' & finish GraphBLAS & \ref{finalize} \\ @@ -1112,30 +1131,37 @@ \subsection{{\sf GrB\_init:} initialize GraphBLAS} %============================ \verb'GrB_Matrix_extractTuples') always finish reading them, or creating them, when the method or operation returns to the user application. +% TODO in 4.0: Revise for v4.0: In addition, all methods and operations that extract values from a GraphBLAS object and return them into non-opaque user arrays always ensure that the computations for that object are completed when the method returns, namely: \verb'GrB_*_nvals', \verb'GrB_*_extractElement', \verb'GrB_*_extractTuples', -and \verb'GrB_*_reduce' (to scalar). These methods only ensure that the -computations for a single object are completed. Use \verb'GrB_wait' -to ensure that all computations are completed (see Section~\ref{wait}). +and \verb'GrB_*_reduce' (to scalar). +{\bf NOTE: this behavior will change in SuiteSparse:GraphBLAS v4.0. These +functions will only guarantee that the user-visible arrays are fully populated; +they will not guarantee completion. Use \verb'GrB_*_wait(&object)' instead.} SuiteSparse:GraphBLAS is multithreaded internally, via OpenMP, and it is also safe to use in a multithreaded user application. See Section~\ref{sec:install} for details. - User threads must not operate on the same matrices at the same time, with one -exception. Multiple threads can use the same matrices or vectors as read-only -inputs to GraphBLAS operations or methods, but only if they have no pending -operations (use \verb'GrB_Matrix_nvals' or \verb'GrB_wait' first). User -threads cannot simultaneously modify a matrix or vector via any GraphBLAS -operation or method. +exception. Multiple user threads can use the same matrices or vectors as +read-only inputs to GraphBLAS operations or methods, but only if they have no +pending operations (use \verb'GrB_Matrix_wait' or \verb'GrB_Vector_wait' +first). User threads cannot simultaneously modify a matrix or vector via any +GraphBLAS operation or method. + +It is safe to use the internal parallelism in SuiteSparse:GraphBLAS on +matrices, vectors, and scalars that are not yet completed. The library +handles this on its own. The \verb'GrB_*_wait(&object)' function is only +needed when a user application makes multiple calls to GraphBLAS in parallel, +from multiple user threads. With multiple user threads, exactly one user thread must call \verb'GrB_init' before any user thread may call any \verb'GrB_*' or \verb'GxB_*' function. -When the user application is finished, exactly one user thread -must call \verb'GrB_finalize', after which no user thread may call -any \verb'GrB_*' or \verb'GxB_*' function. +When the user application is finished, exactly one user thread must call +\verb'GrB_finalize', after which no user thread may call any \verb'GrB_*' or +\verb'GxB_*' function. You can query the mode of a GraphBLAS session with the following (see Section~\ref{options}), which returns the \verb'mode' passed to @@ -1146,6 +1172,42 @@ \subsection{{\sf GrB\_init:} initialize GraphBLAS} %============================ GrB_mode mode ; GxB_get (GxB_MODE, &mode) ; \end{verbatim} } +\newpage +%=============================================================================== +\subsection{{\sf GrB\_getVersion:} determine the C API Version} %=============== +%=============================================================================== +\label{getVersion} + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_getVersion // runtime access to C API version number +( + unsigned int *version, // returns GRB_VERSION + unsigned int *subversion // returns GRB_SUBVERSION +) ; +\end{verbatim} +}\end{mdframed} + +GraphBLAS defines two compile-time constants that +define the version of the C API Specification +that is implemented by the library: +\verb'GRB_VERSION' and \verb'GRB_SUBVERSION'. +If the user program was compiled with one +version of the library but linked with a different one later on, the +compile-time version check with \verb'GRB_VERSION' would be stale. +\verb'GrB_getVersion' thus provides a runtime access of the version of the C +API Specification supported by the library. + +This version of SuiteSparse:GraphBLAS supports +\input{GraphBLAS_API_version.tex} +of the C API Specification, +% TODO in 4.0: Remove when GrB_wait(no inputs) is removed; +except for the polymorphic \verb'GrB_wait(&object)' with one input. +That method will appear in SuiteSparse:GraphBLAS V4.0.0. In the meantime, use +the non-polymorphic methods \verb'GrB_Matrix_wait(&C)', +\verb'GrB_Vector_wait(&v)', and so on. + %=============================================================================== \subsection{{\sf GxB\_init:} initialize with alternate malloc} %====== %=============================================================================== @@ -1193,7 +1255,8 @@ \subsection{{\sf GxB\_init:} initialize with alternate malloc} %====== SuiteSparse:GraphBLAS can be compiled as normal (outside of MATLAB) and then linked into a MATLAB \verb'mexFunction'. However, a \verb'mexFunction' should use the MATLAB memory managers. To do this, use the following instead of -\verb'GrB_init(mode)' in a MATLAB \verb'mexFunction'. +\verb'GrB_init(mode)' in a MATLAB \verb'mexFunction', with the flag +\verb'false' since these functions are not thread-safe: {\footnotesize \begin{verbatim} @@ -1202,7 +1265,15 @@ \subsection{{\sf GxB\_init:} initialize with alternate malloc} %====== ... GxB_init (mode, mxMalloc, mxCalloc, mxRealloc, mxFree, false) ; \end{verbatim}} -As another example, the scalable Intel TBB memory manager can be used: +Passing in the last parameter as \verb'false' requires that GraphBLAS be +compiled with OpenMP. Internally, SuiteSparse:GraphBLAS never calls any memory +management function inside a parallel region. Results are undefined if all +three of the following conditions hold: (1) the user application calls +GraphBLAS in parallel from multiple user-level threads, (2) the memory +functions are not thread-safe, and (3) GraphBLAS is not compiled with OpenMP. +Safety is guaranteed if at least one of those conditions is false. + +To use the scalable Intel TBB memory manager: {\footnotesize \begin{verbatim} @@ -1216,98 +1287,6 @@ \subsection{{\sf GxB\_init:} initialize with alternate malloc} %====== {\bf SPEC:} \verb'GxB_init' is an extension to the spec. \end{spec} -\newpage -%=============================================================================== -\subsection{{\sf GrB\_wait:} wait for pending operations to finish} %=========== -%=============================================================================== -\label{wait} - -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} -GrB_Info GrB_wait ( ) ; // finish all pending computations -\end{verbatim} -}\end{mdframed} - -\verb'GrB_wait' forces all pending operations to complete. -Blocking mode acts as if \verb'GrB_wait' is called whenever a GraphBLAS -method or operation returns to the user application. - -Unless specific rules are followed, non-blocking mode can be unpredictable if -user-defined functions have side effects or if they rely on global variables -not under the control of GraphBLAS. Suppose the user application creates a -user-defined operator that accesses a global variable. That operator is then -used in a GraphBLAS operation, which is left pending. If the user application -then changes the global variable before pending operations complete, the -pending operations will be eventually computed with this different value. - -Worse yet, a user-defined operator might be freed before it is needed to finish -a pending operation. This causes undefined behavior. - -For best results with GraphBLAS, user-defined functions should not have side -effects, nor should they access global variables outside the control of -GraphBLAS. This allows the non-blocking mode to be used at its fullest level -of performance. However, both of these features can safely be used in -user-defined functions if the following specific rules are followed. - -\begin{itemize} - -\item User-defined functions may be called in any order when used in a - GraphBLAS operation. This order may change in non-obvious ways, even in - the same GraphBLAS operation. For example, SuiteSparse:\-GraphBLAS relies - on multiple algorithms for matrix multiplication, and selects between them - automatically. The methods will call user-defined multiply and add - operators in the semiring, in different order. The user application should - not rely on any particular order used in a specific implementation of - GraphBLAS. - -\item User-defined functions are permitted to access global variables. - However, if they do so, the global variables they rely on should not be - changed if any GraphBLAS methods or operations are still pending, assuming - GraphBLAS is executing in non-blocking mode (see Section~\ref{init}). To - ensure this, the user application must call \verb'GrB_wait' before changing - any global variables relied upon by user-defined functions. Alternatively, - computations can be forced to complete on selected matrices and vectors via - \verb'GrB_*_nvals', \verb'GrB_*_extractElement', - \verb'GrB_*_extractTuples', and \verb'GrB_*_reduce' (to scalar) applied to - selected matrices and vectors. The \verb'GrB_*_nvals' function is - particularly well-suited for this purpose since it is otherwise an - extremely light-weight computation in SuiteSparse:GraphBLAS. - -\item If any GraphBLAS methods or operations are still pending, freeing - user-defined types, operators, monoids, semirings, vectors, matrices, or - descriptors leads to undefined behavior. A user application must call - \verb'GrB_wait' before freeing any user-defined object, if a pending - operation relies on it, or by selective completion via, say, - \verb'GrB_*_nvals'. Alternatively, if the user application is about to - terminate GraphBLAS (see \verb'GrB_finalize' below), then all GraphBLAS - objects may be freed in any order, without calling \verb'GrB_wait'. - Pending computations will simply be abandoned. - -\end{itemize} - -\verb'GrB_wait' ensures that all computations are completed for all objects. -For specific objects, \verb'GrB_*_nvals', \verb'GrB_*_extractElement', -\verb'GrB_*_extractTuples', and \verb'GrB_*_reduce' (to scalar) ensure that the -pending operations are completed just for the matrix or vector they operate on. -No other GraphBLAS method or operation guarantees the completion of pending -computations, even though they may happen to do so in any particular -implementation. In the current version, SuiteSparse:GraphBLAS exploits the -non-blocking mode in the \verb'GrB_*_setElement' methods and the -\verb'GrB_assign' and \verb'GxB_subassign' operations. Future versions of -SuiteSparse:GraphBLAS may extend this to other methods and operations. Refer -to the example at the end of Section~\ref{overview}. - -If multiple user threads have created matrices or vectors, and those have -pending operations, then a single call by one thread to \verb'GrB_wait' causes -all pending operations left by all threads to be completed. If other user -threads are working on any of those matrices, this would result in a race -condition. Therefore, \verb'GrB_wait' should be called only when no other user -thread is operating on any other matrix. Functions that cause a specific -matrix to be finalized (\verb'GrB_*_nvals', \verb'GrB_*_extractElement', -\verb'GrB_*_extractTuples', and \verb'GrB_*_reduce' (to scalar)) can be safely -called by multiple user threads on different matrices. - \newpage %=============================================================================== \subsection{{\sf GrB\_Info:} status code returned by GraphBLAS} %=============== @@ -1325,15 +1304,17 @@ \subsection{{\sf GrB\_Info:} status code returned by GraphBLAS} %=============== \begin{tabular}{llp{2.8in}} \hline \verb'GrB_SUCCESS' & 0 & the method or operation was successful \\ -\verb'GrB_NO_VALUE' & 1 & \verb'A(i,j)' requested but not there. - Its value is implicit. \\ +\verb'GrB_NO_VALUE' & 1 & the method was successful, but the entry \\ + & & does not appear in the matrix or vector. \\ + & & Its value is implicit. \\ +\hline \hline \verb'GrB_UNINITIALIZED_OBJECT' & 2 & object has not been initialized \\ \verb'GrB_INVALID_OBJECT' & 3 & object is corrupted \\ \verb'GrB_NULL_POINTER' & 4 & input pointer is \verb'NULL' \\ \verb'GrB_INVALID_VALUE' & 5 & generic error code; some value is bad \\ \verb'GrB_INVALID_INDEX' & 6 & a row or column index is out of bounds; - for indices passed as scalars, not in a list. \\ + for indices passed as scalars, not in a list. \\ \verb'GrB_DOMAIN_MISMATCH' & 7 & object domains are not compatible \\ \verb'GrB_DIMENSION_MISMATCH' & 8 & matrix dimensions do not match \\ \verb'GrB_OUTPUT_NOT_EMPTY' & 9 & output matrix already has values in it \\ @@ -1381,9 +1362,9 @@ \subsection{{\sf GrB\_error:} get more details on the last error} %============= Each GraphBLAS method and operation returns a \verb'GrB_Info' error code. The \verb'GrB_error' function returns additional information on the error in a thread-safe null-terminated string. The string returned by \verb'GrB_error' is -allocated in thread local storage and must not be freed or modified. -Each user thread has its own error status. -The simplest way to use it is just to print it out, such as: +allocated in thread local storage and must not be freed or modified. Each user +thread has its own error status. The simplest way to use it is just to print +it out, such as: {\footnotesize \begin{verbatim} @@ -1405,7 +1386,7 @@ \subsection{{\sf GrB\_error:} get more details on the last error} %============= Successful GraphBLAS methods do not modify the last error message recorded. If a GraphBLAS method fails and then subsequent GraphBLAS method succeeds, the -error message is not modified from the last failure. Only a subsequent failure +error message is not modified from the last failure. A subsequent failure will cause \verb'GrB_error' to return a different error message. Note that \verb'GrB_NO_VALUE' is an not error, but an informational status. @@ -1416,6 +1397,13 @@ \subsection{{\sf GrB\_error:} get more details on the last error} %============= \verb'GrB_error' to print. These include \verb'GrB_PANIC' and errors in \verb'GrB_init' and \verb'GxB_init'. +% TODO in 4.0: revise this statement when the change to the API is finalized: +{\bf NOTE:} \verb'GrB_error' may change in the future. It may have the signature +\verb'GrB_error(&s,C)' where \verb's' is the error string that describes the +error when \verb'C' is the output object of a GraphBLAS method. This change to +the C API is tentative. If this change is made, it will be reflected in +SuiteSparse:GraphBLAS v4.0. + \newpage %=============================================================================== \subsection{{\sf GrB\_finalize:} finish GraphBLAS} %============================ @@ -1435,9 +1423,8 @@ \subsection{{\sf GrB\_finalize:} finish GraphBLAS} %============================ \verb'GrB_finalize' will not free those objects. In non-blocking mode, GraphBLAS may leave some computations as pending. These computations can be safely abandoned if the user application frees all GraphBLAS objects it has -created and then calls \verb'GrB_finalize'. There is no need to call -\verb'GrB_wait' in this case. When the user application is finished, exactly -one user thread must call \verb'GrB_finalize'. +created and then calls \verb'GrB_finalize'. When the user application is +finished, exactly one user thread must call \verb'GrB_finalize'. \newpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1449,8 +1436,9 @@ \section{GraphBLAS Objects and their Methods} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% their scalar data type (or domain), binary and unary operators on scalar types, monoids, semirings, and a {\em descriptor} object used to specify optional parameters that modify the behavior of a GraphBLAS operation. -SuiteSparse:GraphBLAS adds two additional objects: a sparse scalar, and an -operator for selecting entries from a matrix or vector. +SuiteSparse:GraphBLAS adds two additional objects: a sparse scalar +(\verb'GxB_Scalar'), and an operator for selecting entries from a matrix or +vector (\verb'GxB_SelectOp'). The GraphBLAS API makes a distinction between {\em methods} and {\em operations}. A method is a function that works on a GraphBLAS object, creating @@ -1462,19 +1450,17 @@ \section{GraphBLAS Objects and their Methods} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% {\small \begin{tabular}{ll} \hline -\verb'GrB_Type' & a scalar data type \\ -\verb'GrB_UnaryOp' & a unary operator $z=f(x)$, - where $z$ and $x$ are scalars\\ -\verb'GrB_BinaryOp' & a binary operator $z=f(x,y)$, - where $z$, $x$, and $y$ are scalars\\ -\verb'GxB_SelectOp' & a select operator \\ -\verb'GrB_Monoid' & an associative and commutative binary operator \\ - & and its identity value \\ -\verb'GrB_Semiring' & a monoid that defines the ``plus'' and a binary operator\\ - & that defines the ``multiply'' for an algebraic semiring \\ -\verb'GrB_Matrix' & a 2D sparse matrix of any type \\ -\verb'GrB_Vector' & a 1D sparse column vector of any type \\ -\verb'GxB_Scalar' & a sparse scalar of any type \\ +\verb'GrB_Type' & a scalar data type \\ +\verb'GrB_UnaryOp' & a unary operator $z=f(x)$, where $z$ and $x$ are scalars\\ +\verb'GrB_BinaryOp' & a binary operator $z=f(x,y)$, where $z$, $x$, and $y$ are scalars\\ +\verb'GxB_SelectOp' & a select operator \\ +\verb'GrB_Monoid' & an associative and commutative binary operator \\ + & and its identity value \\ +\verb'GrB_Semiring' & a monoid that defines the ``plus'' and a binary operator\\ + & that defines the ``multiply'' for an algebraic semiring \\ +\verb'GrB_Matrix' & a 2D sparse matrix of any type \\ +\verb'GrB_Vector' & a 1D sparse column vector of any type \\ +\verb'GxB_Scalar' & a sparse scalar of any type \\ \verb'GrB_Descriptor'& a collection of parameters that modify an operation \\ \hline \end{tabular} @@ -1487,15 +1473,9 @@ \section{GraphBLAS Objects and their Methods} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% back to GraphBLAS which will do the work. Assigning one handle to another is valid but it does not make a copy of the underlying object. -GraphBLAS provides 11 built-in types and 157 built-in operators; -SuiteSparse:GraphBLAS adds 143 additional built-in operators. With these, -55 unique monoids and 1355 unique semirings can be constructed. - \begin{spec} -{\bf SPEC:} SuiteSparse:GraphBLAS predefines all unique monoids and semirings -that can be constructed from built-in types and operators, as an extension to -the spec. They appear in \verb'GraphBLAS.h'. The \verb'GxB_SelectOp' object -is an extension to GraphBLAS. +{\bf SPEC:} \verb'GxB_SelectOp' and \verb'GxB_Scalar' are extensions to +GraphBLAS. \end{spec} \newpage @@ -1506,11 +1486,15 @@ \subsection{The GraphBLAS type: {\sf GrB\_Type}} %============================== A GraphBLAS \verb'GrB_Type' defines the type of scalar values that a matrix or vector contains, and the type of scalar operands for a unary or binary -operator. There are eleven built-in types, and a user application can define +operator. There are 13 built-in types, and a user application can define any types of its own as well. The built-in types correspond to built-in types in C (\verb'#include ' and \verb'#include '), and the classes in MATLAB, as listed in the following table. +MATLAB allows for \verb'double complex' sparse matrices, but the +\verb'class(A)' for such a matrix is just \verb'double'. MATLAB treats +the complex types as properties of a class. + \vspace{0.2in} \noindent {\footnotesize @@ -1522,24 +1506,32 @@ \subsection{The GraphBLAS type: {\sf GrB\_Type}} %============================== \verb'GrB_BOOL' & \verb'bool' & \verb'logical' & Boolean & true (1), false (0) \\ \hline \verb'GrB_INT8' & \verb'int8_t' & \verb'int8' & 8-bit signed integer & -128 to 127 \\ -\verb'GrB_UINT8' & \verb'uint8_t' & \verb'uint8' & 8-bit unsigned integer & 0 to 255 \\ -\hline \verb'GrB_INT16' & \verb'int16_t' & \verb'int16' & 16-bit integer & $-2^{15}$ to $2^{15}-1$ \\ -\verb'GrB_UINT16' & \verb'uint16_t' & \verb'uint16' & 16-bit unsigned integer & 0 to $2^{16}-1$ \\ -\hline \verb'GrB_INT32' & \verb'int32_t' & \verb'int32' & 32-bit integer & $-2^{31}$ to $2^{31}-1$ \\ -\verb'GrB_UINT32' & \verb'uint32_t' & \verb'uint32' & 32-bit unsigned integer & 0 to $2^{32}-1$ \\ -\hline \verb'GrB_INT64' & \verb'int64_t' & \verb'int64' & 64-bit integer & $-2^{63}$ to $2^{63}-1$ \\ +\hline +\verb'GrB_UINT8' & \verb'uint8_t' & \verb'uint8' & 8-bit unsigned integer & 0 to 255 \\ +\verb'GrB_UINT16' & \verb'uint16_t' & \verb'uint16' & 16-bit unsigned integer & 0 to $2^{16}-1$ \\ +\verb'GrB_UINT32' & \verb'uint32_t' & \verb'uint32' & 32-bit unsigned integer & 0 to $2^{32}-1$ \\ \verb'GrB_UINT64' & \verb'uint64_t' & \verb'uint64' & 64-bit unsigned integer & 0 to $2^{64}-1$ \\ \hline \verb'GrB_FP32' & \verb'float' & \verb'single' & 32-bit IEEE 754 & \verb'-Inf' to \verb'+Inf'\\ \verb'GrB_FP64' & \verb'double' & \verb'double' & 64-bit IEEE 754 & \verb'-Inf' to \verb'+Inf'\\ \hline +\verb'GxB_FC32' & \verb'float complex' & \verb'single' & 32-bit IEEE 754 & \verb'-Inf' to \verb'+Inf'\\ + & & \verb'~isreal(.)' & complex & \\ +\hline +\verb'GxB_FC64' & \verb'double complex' & \verb'double' & 64-bit IEEE 754 & \verb'-Inf' to \verb'+Inf'\\ + & & \verb'~isreal(.)' & complex & \\ +\hline \end{tabular} } \vspace{0.2in} +The ANSI C11 definitions of \verb'float complex' and \verb'double complex' +are not always available. The \verb'GraphBLAS.h' header defines them as +\verb'GxB_FC32_t' and \verb'GxB_FC64_t', respectively. + The user application can also define new types based on any \verb'typedef' in the C language whose values are held in a contiguous region of memory. For example, a user-defined \verb'GrB_Type' could be created to hold any C @@ -1561,6 +1553,7 @@ \subsection{The GraphBLAS type: {\sf GrB\_Type}} %============================== \begin{tabular}{ll} \hline \verb'GrB_Type_new' & create a user-defined type \\ +\verb'GrB_Type_wait' & wait for a user-defined type \\ \verb'GxB_Type_size' & return the size of a type \\ \verb'GrB_Type_free' & free a user-defined type \\ \hline @@ -1648,13 +1641,32 @@ \subsubsection{{\sf GrB\_Type\_new:} create a user-defined type} via \verb'GrB_apply'. An extensive set of complex operators are provided in the \verb'usercomplex.c' example in the \verb'Demo' folder, along with an include file, \verb'usercomplex.h', that is suitable for inclusion in any user -application. Thus, while GraphBLAS does not include any complex types or -operators, SuiteSparse:GraphBLAS provides them in two simple ``user'' files in -the \verb'Demo' folder. -Refer to Section~\ref{user} for more details on these two example user-defined -types. +application. GraphBLAS does not include any complex types or operators, +SuiteSparse:GraphBLAS provides them in two simple ``user'' files in the +\verb'Demo' folder, as user-defined types. They also now appear as built-in +types, \verb'GxB_FC32' and \verb'GxB_FC64'. Refer to Section~\ref{user} for +more details on these example user-defined types. -% \newpage +%------------------------------------------------------------------------------- +\subsubsection{{\sf GrB\_Type\_wait:} wait for a type} +%------------------------------------------------------------------------------- + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_Type_wait // wait for a user-defined type +( + GrB_Type *type // type to wait for +) ; +\end{verbatim} +}\end{mdframed} + +After creating a user-defined type, a GraphBLAS library may choose to exploit +non-blocking mode to delay its creation. \verb'GrB_Type_wait(&type)' ensures +the \verb'type' is completed. SuiteSparse:GraphBLAS currently does nothing for +\verb'GrB_Type_wait(&type)', except to ensure that \verb'type' is valid. + +\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_Type\_size:} return the size of a type} %------------------------------------------------------------------------------- @@ -1678,7 +1690,6 @@ \subsubsection{{\sf GxB\_Type\_size:} return the size of a type} {\bf SPEC:} \verb'GxB_Type_size' is an extension to the spec. \end{spec} -\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Type\_free:} free a user-defined type} %------------------------------------------------------------------------------- @@ -1720,15 +1731,12 @@ \subsubsection{{\sf GrB\_Type\_free:} free a user-defined type} type is freed the matrix can no longer be used. The only safe thing that can be done with such a matrix is to free it. -Note the function signature of \verb'GrB_Type_free', above. It is illustrated -with the generic name, \verb'GrB_free'. Any GraphBLAS object can be freed with -the single function, \verb'GrB_free'. Refer to Section~\ref{free} for more -details. - -GraphBLAS includes many such generic functions. When describing a specific -variation, a function is described with its specific name in this User Guide -(such as \verb'GrB_Type_free'). When discussing features applicable to all -specific forms, the generic name is used instead (such as \verb'GrB_free'). +The function signature of \verb'GrB_Type_free' uses the generic name +\verb'GrB_free', which can free any GraphBLAS object. See Section~\ref{free} +details. GraphBLAS includes many such generic functions. When describing a +specific variation, a function is described with its specific name in this User +Guide (such as \verb'GrB_Type_free'). When discussing features applicable to +all specific forms, the generic name is used instead (such as \verb'GrB_free'). \newpage %=============================================================================== @@ -1739,47 +1747,141 @@ \subsection{GraphBLAS unary operators: {\sf GrB\_UnaryOp}, $z=f(x)$} %========== A unary operator is a scalar function of the form $z=f(x)$. The domain (type) of $z$ and $x$ need not be the same. -There are six kinds of built-in unary operators: -one, identity, additive inverse, absolute value, -multiplicative inverse, and logical negation. In the notation in the table -below, $T$ is any of the 11 built-in types and is a place-holder for -\verb'BOOL', \verb'INT8', \verb'UINT8', ... \verb'FP32', or \verb'FP64'. For -example, \verb'GrB_AINV_INT32' is a unary operator that computes \verb'z=-x' -for two values \verb'x' and \verb'z' of type \verb'GrB_INT32'. +In the notation in the tables +below, $T$ is any of the 13 built-in types and is a place-holder for +\verb'BOOL', \verb'INT8', \verb'UINT8', ... +\verb'FP32', \verb'FP64', \verb'FC32', or \verb'FC64'. +For example, \verb'GrB_AINV_INT32' is a unary operator that computes +\verb'z=-x' for two values \verb'x' and \verb'z' of type \verb'GrB_INT32'. + +The notation $R$ refers to any real type (all but \verb'FC32' and \verb'FC64'), +$I$ refers to any integer type (\verb'INT*' and \verb'UINT*'), +$F$ refers to any real or complex floating point type +(\verb'FP32', \verb'FP64', \verb'FC32', or \verb'FC64'), +and $Z$ refers to any complex floating point type +(\verb'FC32' or \verb'FC64'). The logical negation operator \verb'GrB_LNOT' only works on Boolean types. The -\verb'GxB_LNOT_'$T$ functions operate on inputs of type $T$, implicitly -typecasting their input to Boolean and returning result of type $T$, with a +\verb'GxB_LNOT_'$R$ functions operate on inputs of type $R$, implicitly +typecasting their input to Boolean and returning result of type $R$, with a value 1 for true and 0 for false. The operators \verb'GxB_LNOT_BOOL' and \verb'GrB_LNOT' are identical. -Considering all combinations, there are thus 67 built-in unary operators -((6 kinds of operators) $\times$ (11 types), and \verb'GrB_LNOT'). \vspace{0.2in} {\footnotesize -\begin{tabular}{llll} +\begin{tabular}{|llll|} +\hline +\multicolumn{4}{|c|}{Unary operators for all types} \\ \hline -GraphBLAS name & types (domains) & expression & description \\ - & & $z=f(x)$ & \\ +GraphBLAS name & types (domains) & $z=f(x)$ & description \\ \hline \verb'GxB_ONE_'$T$ & $T \rightarrow T$ & $z = 1$ & one \\ \verb'GrB_IDENTITY_'$T$ & $T \rightarrow T$ & $z = x$ & identity \\ \verb'GrB_AINV_'$T$ & $T \rightarrow T$ & $z = -x$ & additive inverse \\ -\verb'GxB_ABS_'$T$ & $T \rightarrow T$ & $z = |x|$ & absolute value \\ \verb'GrB_MINV_'$T$ & $T \rightarrow T$ & $z = 1/x$ & multiplicative inverse \\ -\verb'GxB_LNOT_'$T$ & $T \rightarrow T$ & $z = \lnot (x \ne 0)$ & logical negation \\ \hline +\end{tabular} +\vspace{0.2in} + +\vspace{0.2in} +\begin{tabular}{|llll|} +\hline +\multicolumn{4}{|c|}{Unary operators for real and integer types} \\ +\hline +GraphBLAS name & types (domains) & $z=f(x)$ & description \\ +\hline +\verb'GrB_ABS_'$T$ & $R \rightarrow R$ & $z = |x|$ & absolute value \\ \verb'GrB_LNOT' & \verb'bool' $\rightarrow$ \verb'bool' & $z = \lnot x$ & logical negation \\ +\verb'GxB_LNOT_'$R$ & $R \rightarrow R$ & $z = \lnot (x \ne 0)$ & logical negation \\ +\verb'GrB_BNOT_'$I$ & $I \rightarrow I$ & $z = \lnot x$ & bitwise negation \\ \hline \end{tabular} -} \vspace{0.2in} -\begin{spec} -{\bf SPEC:} \verb'GxB_ONE_'$T$, \verb'GxB_ABS_'$T$ and \verb'GxB_LNOT_'$T$ are extensions to the spec. -\end{spec} +\begin{tabular}{|llll|} +\hline +\multicolumn{4}{|c|}{Unary operators for floating-point types (real and complex)} \\ +\hline +GraphBLAS name & types (domains) & $z=f(x)$ & description \\ +\hline +\verb'GxB_SQRT_'$F$ & $F \rightarrow F$ & $z = \sqrt(x)$ & square root \\ +\verb'GxB_LOG_'$F$ & $F \rightarrow F$ & $z = \log_e(x)$ & natural logarithm \\ +\verb'GxB_EXP_'$F$ & $F \rightarrow F$ & $z = e^x$ & natural exponent \\ +\hline +\verb'GxB_LOG10_'$F$ & $F \rightarrow F$ & $z = \log_{10}(x)$ & base-10 logarithm \\ +\verb'GxB_LOG2_'$F$ & $F \rightarrow F$ & $z = \log_2(x)$ & base-2 logarithm \\ +\verb'GxB_EXP2_'$F$ & $F \rightarrow F$ & $z = 2^x$ & base-2 exponent \\ +\hline +\verb'GxB_EXPM1_'$F$ & $F \rightarrow F$ & $z = e^x - 1$ & natural exponent - 1 \\ +\verb'GxB_LOG1P_'$F$ & $F \rightarrow F$ & $z = \log(x+1)$ & natural log of $x+1$ \\ +\hline +\verb'GxB_SIN_'$F$ & $F \rightarrow F$ & $z = \sin(x)$ & sine \\ +\verb'GxB_COS_'$F$ & $F \rightarrow F$ & $z = \cos(x)$ & cosine \\ +\verb'GxB_TAN_'$F$ & $F \rightarrow F$ & $z = \tan(x)$ & tangent \\ +\hline +\verb'GxB_ASIN_'$F$ & $F \rightarrow F$ & $z = \sin^{-1}(x)$ & inverse sine \\ +\verb'GxB_ACOS_'$F$ & $F \rightarrow F$ & $z = \cos^{-1}(x)$ & inverse cosine \\ +\verb'GxB_ATAN_'$F$ & $F \rightarrow F$ & $z = \tan^{-1}(x)$ & inverse tangent \\ +\hline +\verb'GxB_SINH_'$F$ & $F \rightarrow F$ & $z = \sinh(x)$ & hyperbolic sine \\ +\verb'GxB_COSH_'$F$ & $F \rightarrow F$ & $z = \cosh(x)$ & hyperbolic cosine \\ +\verb'GxB_TANH_'$F$ & $F \rightarrow F$ & $z = \tanh(x)$ & hyperbolic tangent \\ +\hline +\verb'GxB_ASINH_'$F$ & $F \rightarrow F$ & $z = \sinh^{-1}(x)$ & inverse hyperbolic sine \\ +\verb'GxB_ACOSH_'$F$ & $F \rightarrow F$ & $z = \cosh^{-1}(x)$ & inverse hyperbolic cosine \\ +\verb'GxB_ATANH_'$F$ & $F \rightarrow F$ & $z = \tanh^{-1}(x)$ & inverse hyperbolic tangent \\ +\hline +\verb'GxB_SIGNUM_'$F$ & $F \rightarrow F$ & $z = \sgn(x)$ & sign, or signum function \\ +\verb'GxB_CEIL_'$F$ & $F \rightarrow F$ & $z = \lceil x \rceil $ & ceiling function \\ +\verb'GxB_FLOOR_'$F$ & $F \rightarrow F$ & $z = \lfloor x \rfloor $ & floor function \\ +\verb'GxB_ROUND_'$F$ & $F \rightarrow F$ & $z = \mbox{round}(x)$ & round to nearest \\ +\verb'GxB_TRUNC_'$F$ & $F \rightarrow F$ & $z = \mbox{trunc}(x)$ & round towards zero \\ +\hline +\verb'GxB_LGAMMA_'$F$ & $F \rightarrow F$ & $z = \log(|\Gamma (x)|)$ & log of gamma function \\ +\verb'GxB_TGAMMA_'$F$ & $F \rightarrow F$ & $z = \Gamma(x)$ & gamma function \\ +\verb'GxB_ERF_'$F$ & $F \rightarrow F$ & $z = \erf(x)$ & error function \\ +\verb'GxB_ERFC_'$F$ & $F \rightarrow F$ & $z = \erfc(x)$ & complimentary error function \\ +\hline +\verb'GxB_FREXPX_'$F$ & $F \rightarrow F$ & $z = \mbox{frexpx}(x)$ & normalized fraction \\ +\verb'GxB_FREXPE_'$F$ & $F \rightarrow F$ & $z = \mbox{frexpe}(x)$ & normalized exponent \\ +\hline +\verb'GxB_ISINF_'$F$ & $F \rightarrow $ \verb'bool' & $z = \mbox{isinf}(x)$ & true if $\pm \infty$ \\ +\verb'GxB_ISNAN_'$F$ & $F \rightarrow $ \verb'bool' & $z = \mbox{isnan}(x)$ & true if \verb'NaN' \\ +\verb'GxB_ISFINITE_'$F$ & $F \rightarrow $ \verb'bool' & $z = \mbox{isfinite}(x)$ & true if finite \\ +\hline +\end{tabular} +\vspace{0.2in} + +\verb'GxB_FREXPX' \verb'GxB_FREXPE' return the mantissa and exponent, respectively, +from the ANSI C11 \verb'frexp' function. The exponent is returned as a +floating-point value, not an integer. + +The functions \verb'casin', \verb'casinf', \verb'casinh', and \verb'casinhf' +provided by Microsoft Visual Studio for computing $\sin^{-1}(x)$ and +$\sinh^{-1}(x)$ when $x$ is complex do not compute the correct result. Thus, +the unary operators \verb'GxB_ASIN_FC32', \verb'GxB_ASIN_FC64' +\verb'GxB_ASINH_FC32', and \verb'GxB_ASINH_FC64' do not work properly if the MS +Visual Studio compiler is used. These functions work properly if the gcc, icc, +or clang compilers are used on Linux or MacOS. + +\vspace{0.2in} +\begin{tabular}{|llll|} +\hline +\multicolumn{4}{|c|}{Unary operators for complex types} \\ +\hline +GraphBLAS name & types (domains) & $z=f(x)$ & description \\ +\hline +\verb'GxB_CONJ_'$Z$ & $Z \rightarrow Z$ & $z = \overline{x}$ & complex conjugate \\ +\verb'GxB_ABS_'$Z$ & $Z \rightarrow F$ & $z = |x|$ & absolute value \\ +\verb'GxB_CREAL_'$Z$ & $Z \rightarrow F$ & $z = \mbox{real}(x)$ & real part \\ +\verb'GxB_CIMAG_'$Z$ & $Z \rightarrow F$ & $z = \mbox{imag}(x)$ & imaginary part \\ +\verb'GxB_CARG_'$Z$ & $Z \rightarrow F$ & $z = \mbox{carg}(x)$ & angle \\ +\hline +\end{tabular} +} +\vspace{0.2in} Integer division by zero normally terminates an application, but this is avoided in SuiteSparse:GraphBLAS. For details, see the binary @@ -1797,6 +1899,7 @@ \subsection{GraphBLAS unary operators: {\sf GrB\_UnaryOp}, $z=f(x)$} %========== \begin{tabular}{ll} \hline \verb'GrB_UnaryOp_new' & create a user-defined unary operator \\ +\verb'GrB_UnaryOp_wait' & wait for a user-defined unary operator \\ \verb'GxB_UnaryOp_ztype' & return the type of the output $z$ for $z=f(x)$\\ \verb'GxB_UnaryOp_xtype' & return the type of the input $x$ for $z=f(x)$\\ \verb'GrB_UnaryOp_free' & free a user-defined unary operator \\ @@ -1853,7 +1956,27 @@ \subsubsection{{\sf GrB\_UnaryOp\_new:} create a user-defined unary operator} % SPEC: the spec is silent on aliasing in user-defined functions -\newpage +%------------------------------------------------------------------------------- +\subsubsection{{\sf GrB\_UnaryOp\_wait:} wait for a unary operator} +%------------------------------------------------------------------------------- + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_UnaryOp_wait // wait for a user-defined unary operator +( + GrB_UnaryOp *unaryop // unary operator to wait for +) ; +\end{verbatim} +}\end{mdframed} + +After creating a user-defined unary operator, a GraphBLAS library may choose to +exploit non-blocking mode to delay its creation. +\verb'GrB_UnaryOp_wait(&unaryop)' ensures the \verb'op' is completed. +SuiteSparse:GraphBLAS currently does nothing for +\verb'GrB_UnaryOp_wait(&unaryop)', except to ensure that the \verb'unaryop' is +valid. + %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_UnaryOp\_ztype:} return the type of $z$} %------------------------------------------------------------------------------- @@ -1937,102 +2060,127 @@ \subsection{GraphBLAS binary operators: {\sf GrB\_BinaryOp}, $z=f(x,y)$} %====== \label{binaryop} A binary operator is a scalar function of the form $z=f(x,y)$. The types of -$z$, $x$, and $y$ need not be the same. - -SuiteSparse:GraphBLAS has 21 kinds of built-in binary operators of the form $T -\times T \rightarrow T$ that work on all 11 of the built-in types, $T$. -These are listed in the table -below. For each of these operators, all domains (types) of the three operands -are the same. The six comparison operators and the logical operators all -return a result one for true and zero for false, in the same domain $T$ as +$z$, $x$, and $y$ need not be the same. The built-in binary operators are +listed in the tables below. The notation $T$ refers to any of the 13 +built-in types, but two of those types are SuiteSparse extensions +(\verb'GxB_FC32' and \verb'GxB_FC64'). For those types, the operator name +always starts with \verb'GxB', not \verb'GrB'). + +The six \verb'GxB_IS*' comparison operators and the \verb'GxB_*' logical operators all +return a result one for true and zero for false, in the same domain $T$ or $R$ as their inputs. These six comparison operators are useful as ``multiply'' operators for creating semirings with non-Boolean monoids. \vspace{0.2in} {\footnotesize -\begin{tabular}{llll} +\begin{tabular}{|llll|} \hline -GraphBLAS & types (domains) & expression & description \\ -name & & $z=f(x,y)$ & \\ +\multicolumn{4}{|c|}{Binary operators for all 13 types} \\ +\hline +GraphBLAS name & types (domains) & $z=f(x,y)$ & description \\ \hline % numeric TxT->T \verb'GrB_FIRST_'$T$ & $T \times T \rightarrow T$ & $z = x$ & first argument \\ \verb'GrB_SECOND_'$T$ & $T \times T \rightarrow T$ & $z = y$ & second argument \\ \verb'GxB_ANY_'$T$ & $T \times T \rightarrow T$ & $z = x$ or $y$ & pick $x$ or $y$ arbitrarily \\ \verb'GxB_PAIR_'$T$ & $T \times T \rightarrow T$ & $z = 1$ & one \\ -\verb'GrB_MIN_'$T$ & $T \times T \rightarrow T$ & $z = \min(x,y)$ & minimum \\ -\verb'GrB_MAX_'$T$ & $T \times T \rightarrow T$ & $z = \max(x,y)$ & maximum \\ \verb'GrB_PLUS_'$T$ & $T \times T \rightarrow T$ & $z = x+y$ & addition \\ \verb'GrB_MINUS_'$T$ & $T \times T \rightarrow T$ & $z = x-y$ & subtraction \\ \verb'GxB_RMINUS_'$T$ & $T \times T \rightarrow T$ & $z = y-x$ & reverse subtraction \\ \verb'GrB_TIMES_'$T$ & $T \times T \rightarrow T$ & $z = xy$ & multiplication \\ \verb'GrB_DIV_'$T$ & $T \times T \rightarrow T$ & $z = x/y$ & division \\ \verb'GxB_RDIV_'$T$ & $T \times T \rightarrow T$ & $z = y/x$ & reverse division \\ +\verb'GxB_POW_'$T$ & $T \times T \rightarrow T$ & $z = x^y$ & power \\ \hline % TxT->T comparison \verb'GxB_ISEQ_'$T$ & $T \times T \rightarrow T$ & $z = (x == y)$ & equal \\ \verb'GxB_ISNE_'$T$ & $T \times T \rightarrow T$ & $z = (x \ne y)$ & not equal \\ -\verb'GxB_ISGT_'$T$ & $T \times T \rightarrow T$ & $z = (x > y)$ & greater than \\ -\verb'GxB_ISLT_'$T$ & $T \times T \rightarrow T$ & $z = (x < y)$ & less than \\ -\verb'GxB_ISGE_'$T$ & $T \times T \rightarrow T$ & $z = (x \ge y)$ & greater than or equal \\ -\verb'GxB_ISLE_'$T$ & $T \times T \rightarrow T$ & $z = (x \le y)$ & less than or equal \\ -\hline -% TxT->T logical -\verb'GxB_LOR_'$T$ & $T \times T \rightarrow T$ & $z = (x \ne 0) \vee (y \ne 0) $ & logical OR \\ -\verb'GxB_LAND_'$T$ & $T \times T \rightarrow T$ & $z = (x \ne 0) \wedge (y \ne 0) $ & logical AND \\ -\verb'GxB_LXOR_'$T$ & $T \times T \rightarrow T$ & $z = (x \ne 0) \veebar (y \ne 0) $ & logical XOR \\ \hline \end{tabular} } \vspace{0.2in} -\begin{spec} -{\bf SPEC:} The \verb'GxB_IS*_'$T$ -\verb'GxB_RMINUS_'$T$, -\verb'GxB_RDIV_'$T$ -\verb'GxB_ANY_'$T$, -and -\verb'GxB_PAIR_'$T$, -operators, and the Boolean \verb'GxB_L*_'$T$ are extensions to the spec. -\end{spec} +The \verb'GxB_POW_*' operators for real types do not return a complex result, +and thus $z = f(x,y) = x^y$ is undefined if $x$ is negative and $y$ is not an +integer. To compute a complex result, use \verb'GxB_POW_FC32' or +\verb'GxB_POW_FC64'. + +Operators that require the domain to be ordered (\verb'MIN', \verb'MAX', and +relative comparisons less-than, greater-than, and so on) are not defined for +complex types. These are listed in the following table: + +\vspace{0.2in} +{\footnotesize +\begin{tabular}{|llll|} +\hline +\multicolumn{4}{|c|}{Binary operators for all non-complex types} \\ +\hline +GraphBLAS name & types (domains) & $z=f(x,y)$ & description \\ +\hline +% numeric RxR->R +\verb'GrB_MIN_'$R$ & $R \times R \rightarrow R$ & $z = \min(x,y)$ & minimum \\ +\verb'GrB_MAX_'$R$ & $R \times R \rightarrow R$ & $z = \max(x,y)$ & maximum \\ +\hline +% RxR->R comparison +\verb'GxB_ISGT_'$R$ & $R \times R \rightarrow R$ & $z = (x > y)$ & greater than \\ +\verb'GxB_ISLT_'$R$ & $R \times R \rightarrow R$ & $z = (x < y)$ & less than \\ +\verb'GxB_ISGE_'$R$ & $R \times R \rightarrow R$ & $z = (x \ge y)$ & greater than or equal \\ +\verb'GxB_ISLE_'$R$ & $R \times R \rightarrow R$ & $z = (x \le y)$ & less than or equal \\ +\hline +% RxR->R logical +\verb'GxB_LOR_'$R$ & $R \times R \rightarrow R$ & $z = (x \ne 0) \vee (y \ne 0) $ & logical OR \\ +\verb'GxB_LAND_'$R$ & $R \times R \rightarrow R$ & $z = (x \ne 0) \wedge (y \ne 0) $ & logical AND \\ +\verb'GxB_LXOR_'$R$ & $R \times R \rightarrow R$ & $z = (x \ne 0) \veebar (y \ne 0) $ & logical XOR \\ +\hline +\end{tabular} +} +\vspace{0.2in} -\newpage Another set of six kinds of built-in comparison operators have the form $T -\times T \rightarrow $\verb'bool'. They are defined for all eleven built-in -types, for a total of 66 binary operators. Note that when $T$ is \verb'bool', -the six operators give the same results as the six \verb'GxB_IS*_BOOL' -operators in the table above. These six comparison operators are useful as -``multiply'' operators for creating semirings with Boolean monoids. +\times T \rightarrow $\verb'bool'. Note that when $T$ is \verb'bool', the six +operators give the same results as the six \verb'GxB_IS*_BOOL' operators in the +table above. These six comparison operators are useful as ``multiply'' +operators for creating semirings with Boolean monoids. \vspace{0.2in} {\footnotesize -\begin{tabular}{llll} +\begin{tabular}{|llll|} +\hline +\multicolumn{4}{|c|}{Binary comparison operators for all 13 types} \\ \hline -GraphBLAS & types (domains) & expression & description \\ -name & & $z=f(x,y)$ & \\ +GraphBLAS name & types (domains) & $z=f(x,y)$ & description \\ \hline % 6 TxT->bool comparison \verb'GrB_EQ_'$T$ & $T \times T \rightarrow $\verb'bool' & $z = (x == y)$ & equal \\ \verb'GrB_NE_'$T$ & $T \times T \rightarrow $\verb'bool' & $z = (x \ne y)$ & not equal \\ -\verb'GrB_GT_'$T$ & $T \times T \rightarrow $\verb'bool' & $z = (x > y)$ & greater than \\ -\verb'GrB_LT_'$T$ & $T \times T \rightarrow $\verb'bool' & $z = (x < y)$ & less than \\ -\verb'GrB_GE_'$T$ & $T \times T \rightarrow $\verb'bool' & $z = (x \ge y)$ & greater than or equal \\ -\verb'GrB_LE_'$T$ & $T \times T \rightarrow $\verb'bool' & $z = (x \le y)$ & less than or equal \\ +\hline +\multicolumn{4}{ }{\mbox{ }} \\ +\hline +\multicolumn{4}{|c|}{Binary comparison operators for non-complex types} \\ +\hline +GraphBLAS name & types (domains) & $z=f(x,y)$ & description \\ +\hline +\verb'GrB_GT_'$R$ & $R \times R \rightarrow $\verb'bool' & $z = (x > y)$ & greater than \\ +\verb'GrB_LT_'$R$ & $R \times R \rightarrow $\verb'bool' & $z = (x < y)$ & less than \\ +\verb'GrB_GE_'$R$ & $R \times R \rightarrow $\verb'bool' & $z = (x \ge y)$ & greater than or equal \\ +\verb'GrB_LE_'$R$ & $R \times R \rightarrow $\verb'bool' & $z = (x \le y)$ & less than or equal \\ \hline \end{tabular} } \vspace{0.2in} -Finally, GraphBLAS has three built-in binary operators that operate purely in -the Boolean domain. These three are identical to the \verb'GxB_L*_BOOL' -operators described above, just with a shorter name. +GraphBLAS has four built-in binary operators that operate purely in +the Boolean domain. The first three are identical to the \verb'GxB_L*_BOOL' +operators described above, just with a shorter name. The \verb'GrB_LXNOR' +operator is the same as \verb'GrB_EQ_BOOL'. \vspace{0.2in} {\footnotesize -\begin{tabular}{llll} +\begin{tabular}{|llll|} +\hline +\multicolumn{4}{|c|}{Binary operators for the boolean type only} \\ \hline -GraphBLAS & types (domains) & expression & description \\ -name & & $z=f(x,y)$ & \\ +GraphBLAS name & types (domains) & $z=f(x,y)$ & description \\ \hline % 3 bool x bool -> bool \verb'GrB_LOR' & \verb'bool' @@ -2044,6 +2192,57 @@ \subsection{GraphBLAS binary operators: {\sf GrB\_BinaryOp}, $z=f(x,y)$} %====== \verb'GrB_LXOR' & \verb'bool' $\times$ \verb'bool' $\rightarrow$ \verb'bool' & $z = x \veebar y $ & logical XOR \\ +\verb'GrB_LXNOR' & \verb'bool' + $\times$ \verb'bool' + $\rightarrow$ \verb'bool' & $z = \lnot (x \veebar y) $ & logical XNOR \\ +\hline +\end{tabular} +} +\vspace{0.2in} + +The following operators are defined for real floating-point types only (\verb'GrB_FP32' and \verb'GrB_FP64'). +They are identical to the ANSI C11 functions of the same name. The last one in the table constructs +the corresponding complex type. + +{\footnotesize +\begin{tabular}{|llll|} +\hline +\multicolumn{4}{|c|}{Binary operators for the real floating-point types only} \\ +\hline +GraphBLAS name & types (domains) & $z=f(x,y)$ & description \\ +\hline +\verb'GxB_ATAN2_'$F$ & $F \times F \rightarrow F$ & $z = \tan^{-1}(y/x)$ & 4-quadrant arc tangent \\ +\verb'GxB_HYPOT_'$F$ & $F \times F \rightarrow F$ & $z = \sqrt{x^2+y^2}$ & hypotenuse \\ +\verb'GxB_FMOD_'$F$ & $F \times F \rightarrow F$ & & ANSI C11 \verb'fmod' \\ +\verb'GxB_REMAINDER_'$F$ & $F \times F \rightarrow F$ & & ANSI C11 \verb'remainder' \\ +\verb'GxB_LDEXP_'$F$ & $F \times F \rightarrow F$ & & ANSI C11 \verb'ldexp' \\ +\verb'GxB_COPYSIGN_'$F$ & $F \times F \rightarrow F$ & & ANSI C11 \verb'copysign' \\ +\hline +\verb'GxB_CMPLX_'$F$ & $F \times F \rightarrow Z$ & $z = x + y \times i$ & complex from real \& imag \\ +\hline +\end{tabular} +} +\vspace{0.2in} + +Finally, eight bitwise operators are predefined for signed and unsigned integers. + +\vspace{0.2in} +{\footnotesize +\begin{tabular}{|llll|} +\hline +\multicolumn{4}{|c|}{Binary operators for signed and unsigned integers} \\ +\hline +GraphBLAS name & types (domains) & $z=f(x,y)$ & description \\ +\hline +\verb'GrB_BOR_'$I$ & $I \times I \rightarrow I$ & \verb'z=x|y' & bitwise logical OR \\ +\verb'GrB_BAND_'$I$ & $I \times I \rightarrow I$ & \verb'z=x&y' & bitwise logical AND \\ +\verb'GrB_BXOR_'$I$ & $I \times I \rightarrow I$ & \verb'z=x^y' & bitwise logical XOR \\ +\verb'GrB_BXNOR_'$I$ & $I \times I \rightarrow I$ & \verb'z=~(x^y)' & bitwise logical XNOR \\ +\hline +\verb'GxB_BGET_'$I$ & $I \times I \rightarrow I$ & & get bit y of x \\ +\verb'GxB_BSET_'$I$ & $I \times I \rightarrow I$ & & set bit y of x \\ +\verb'GxB_BCLR_'$I$ & $I \times I \rightarrow I$ & & clear bit y of x \\ +\verb'GxB_BSHIFT_'$I$ & $I \times $\verb'int8'$ \rightarrow I$ & & bit shift \\ \hline \end{tabular} } @@ -2070,7 +2269,7 @@ \subsection{GraphBLAS binary operators: {\sf GrB\_BinaryOp}, $z=f(x,y)$} %====== \verb'GrB_LAND', and \verb'GrB_LXOR' operate purely in the Boolean domain, where all input and output types are \verb'GrB_BOOL'. The second set (\verb'GxB_LOR_'$T$ \verb'GxB_LAND_'$T$ and \verb'GxB_LXOR_'$T$) provides -Boolean operators to all 11 domains, implicitly typecasting their inputs from +Boolean operators to all 11 real domains, implicitly typecasting their inputs from type $T$ to Boolean and returning a value of type $T$ that is 1 for true or zero for false. The set of \verb'GxB_L*_'$T$ operators are useful since they can be combined with non-Boolean monoids in a semiring. @@ -2099,6 +2298,7 @@ \subsection{GraphBLAS binary operators: {\sf GrB\_BinaryOp}, $z=f(x,y)$} %====== \begin{tabular}{ll} \hline \verb'GrB_BinaryOp_new' & create a user-defined binary operator \\ +\verb'GrB_BinaryOp_wait' & wait for a user-defined binary operator \\ \verb'GxB_BinaryOp_ztype' & return the type of the output $z$ for $z=f(x,y)$\\ \verb'GxB_BinaryOp_xtype' & return the type of the input $x$ for $z=f(x,y)$\\ \verb'GxB_BinaryOp_ytype' & return the type of the input $y$ for $z=f(x,y)$\\ @@ -2154,9 +2354,26 @@ \subsubsection{{\sf GrB\_BinaryOp\_new:} create a user-defined binary operator} \verb'z' and \verb'x' equal to one another, in which case \verb'z=f(z,y)' should be computed. Future versions may use additional pointer aliasing. -% V2.0.3 and earlier: -% The pointers will be unique. That is, the user function is never called with -% pointers that point to the same space. +%------------------------------------------------------------------------------- +\subsubsection{{\sf GrB\_BinaryOp\_wait:} wait for a binary operator} +%------------------------------------------------------------------------------- + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_BinaryOp_wait // wait for a user-defined binary operator +( + GrB_BinaryOp *binaryop // binary operator to wait for +) ; +\end{verbatim} +}\end{mdframed} + +After creating a user-defined binary operator, a GraphBLAS library may choose +to exploit non-blocking mode to delay its creation. +\verb'GrB_BinaryOp_wait(&binaryop)' ensures the \verb'binaryop' is completed. +SuiteSparse:GraphBLAS currently does nothing for +\verb'GrB_BinaryOp_wait(&binaryop)', except to ensure that the \verb'binaryop' +is valid. % \newpage %------------------------------------------------------------------------------- @@ -2231,7 +2448,7 @@ \subsubsection{{\sf GxB\_BinaryOp\_ytype:} return the type of $y$} {\bf SPEC:} \verb'GxB_BinaryOp_ytype' is an extension to the spec. \end{spec} -% \newpage +\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_BinaryOp\_free:} free a user-defined binary operator} %------------------------------------------------------------------------------- @@ -2261,7 +2478,6 @@ \subsubsection{{\sf GrB\_BinaryOp\_free:} free a user-defined binary operator} handle, or if \verb'op == NULL' on input. It does nothing at all if passed a built-in binary operator. -\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf ANY} and {\sf PAIR} operators} %------------------------------------------------------------------------------- @@ -2297,16 +2513,16 @@ \subsubsection{{\sf ANY} and {\sf PAIR} operators} The result of the \verb'ANY' monoid is non-deterministic, unless it is coupled with the \verb'PAIR' multiplicative operator. In this case, the \verb'ANY_PAIR' semiring will return a deterministic result, -since $f(1,1)$ is always 1, for the \verb'ANY' operator. +since $f(1,1)$ is always 1, for the \verb'ANY' operator $f(x,y)$. When paired with a different operator, the results are non-deterministic. This gives a powerful method when computing results for which any value selected by the \verb'ANY' operator is valid. One such example is the breadth-first-search tree. Suppose node $j$ is at level $v$, and there are multiple nodes $i$ at -level $v-1$ for which edge $(i,j)$ exists in the graph. Any of these nodes $i$ -can serve as a valid parent in the BFS tree. Using the \verb'ANY' operator, -GraphBLAS can quickly compute a valid BFS tree; if it used again on the -same inputs, it might return a different, yet still valid, BFS tree, due to +level $v-1$ for which the edge $(i,j)$ exists in the graph. Any of these nodes +$i$ can serve as a valid parent in the BFS tree. Using the \verb'ANY' +operator, GraphBLAS can quickly compute a valid BFS tree; if it used again on +the same inputs, it might return a different, yet still valid, BFS tree, due to the non-deterministic nature of intra-thread synchronization. \newpage @@ -2386,6 +2602,7 @@ \subsection{SuiteSparse:GraphBLAS select operators: {\sf GxB\_SelectOp}} %====== \begin{tabular}{ll} \hline \verb'GxB_SelectOp_new' & create a user-defined select operator \\ +\verb'GxB_SelectOp_wait' & wait for a user-defined select operator \\ \verb'GxB_SelectOp_xtype' & return the type of the input $x$ \\ \verb'GxB_SelectOp_ttype' & return the type of the input {\em thunk} \\ \verb'GxB_SelectOp_free' & free a user-defined select operator \\ @@ -2434,7 +2651,27 @@ \subsubsection{{\sf GxB\_SelectOp\_new:} create a user-defined select operator} The \verb'const void *thunk' parameter on input to the user \verb'function' will be passed as \verb'NULL'. -\newpage +%------------------------------------------------------------------------------- +\subsubsection{{\sf GB\_SelectOp\_wait:} wait for a select operator} +%------------------------------------------------------------------------------- + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GxB_SelectOp_wait // wait for a user-defined select operator +( + GxB_SelectOp *selectop // select operator to wait for +) ; +\end{verbatim} +}\end{mdframed} + +After creating a user-defined select operator, a GraphBLAS library may choose +to exploit non-blocking mode to delay its creation. +\verb'GxB_SelectOp_wait(&selectop)' ensures the \verb'selectop' is completed. +SuiteSparse:GraphBLAS currently does nothing for +\verb'GxB_SelectOp_wait(&selectop)', except to ensure that the \verb'selectop' +is valid. + %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_SelectOp\_xtype:} return the type of $x$} %------------------------------------------------------------------------------- @@ -2456,7 +2693,7 @@ \subsubsection{{\sf GxB\_SelectOp\_xtype:} return the type of $x$} which is the type of $x$ in the function $z=f(i,j,m,n,x,\mbox{thunk})$. If the select operator is type-generic, \verb'xtype' is returned as \verb'GrB_NULL'. This is not an error condition, but simply indicates that the -\verb'GxB_SelectOp' is type-generic. +\verb'selectop' is type-generic. %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_SelectOp\_ttype:} return the type of the {\em thunk}} @@ -2479,7 +2716,7 @@ \subsubsection{{\sf GxB\_SelectOp\_ttype:} return the type of the {\em thunk}} which is the type of {\em thunk} in the function $z=f(i,j,m,n,x,\mbox{thunk})$. If the select operator does not use this parameter, \verb'ttype' is returned as \verb'GrB_NULL'. This is not an error condition, but simply indicates that the -\verb'GxB_SelectOp' does not use this parameter. +\verb'selectop' does not use this parameter. %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_SelectOp\_free:} free a user-defined select operator} @@ -2518,27 +2755,18 @@ \subsection{GraphBLAS monoids: {\sf GrB\_Monoid}} %============================= consists of an associative binary operator $z=f(x,y)$ whose three operands $x$, $y$, and $z$ are all in this same domain $T$ (that is $T \times T \rightarrow T$). The associative operator must also have an identity element, or ``zero'' -in this domain, such that $f(x,0)=f(0,x)=0$. Recall that an associative +in this domain, such that $f(x,0)=f(0,x)=x$. Recall that an associative operator $f(x,y)$ is one for which the condition $f(a, f(b,c)) = f(f (a,b),c)$ always holds. That is, operator can be applied in any order and the results remain the same. -Five kinds of built-in operators (\verb'MIN', \verb'MAX', \verb'PLUS', -\verb'TIMES', and \verb'ANY') can be used to form monoids for each of the ten -non-Boolean built-in types, and 12 can be used for Boolean monoids, all of -which are listed in the table below. These are the valid monoids that can be -constructed from built-in types and operators, although 8 of the 13 Boolean -monoids are redundant (the four remaining being \verb'OR', \verb'AND', -\verb'XOR', \verb'EQ', and \verb'ANY'). There are a total of 55 unique monoids -that can be constructed using built-in binary operators: five for each of the -the 10 non-Boolean types, and 5 more for Boolean types. Since the built-in -monoids are also commutative, all of them can be used to create a semiring. -Recall that a commutative operator $f(x,y)$ is one for which the condition -$f(a,b)=f(b,a)$ always holds. That is, the two operands can be swapped and the -results remain the same. One of the components of a semiring is a commutative -monoid. +Predefined binary operators that can be used to form monoids are listed in the +table below. Most of these are the binary operators of predefined monoids, +except that the bitwise monoids are predefined only for the unsigned integer +types, not the signed integers. \vspace{0.2in} +\noindent {\footnotesize \begin{tabular}{lllll} \hline @@ -2546,17 +2774,24 @@ \subsection{GraphBLAS monoids: {\sf GrB\_Monoid}} %============================= operator & & $z=f(x,y)$ & & \\ \hline % numeric TxT->T -\verb'GrB_MIN_'$T$ & $T \times T \rightarrow T$ & $z = \min(x,y)$ & $+\infty$ & $-\infty$ \\ -\verb'GrB_MAX_'$T$ & $T \times T \rightarrow T$ & $z = \max(x,y)$ & $-\infty$ & $+\infty$ \\ \verb'GrB_PLUS_'$T$ & $T \times T \rightarrow T$ & $z = x+y$ & 0 & none \\ -\verb'GrB_TIMES_'$T$ & $T \times T \rightarrow T$ & $z = xy$ & 1 & 0 (not fp) \\ +\verb'GrB_TIMES_'$T$ & $T \times T \rightarrow T$ & $z = xy$ & 1 & 0 (not $F$) \\ \verb'GxB_ANY_'$T$ & $T \times T \rightarrow T$ & $z = x$ or $y$ & any & any \\ \hline +\verb'GrB_MIN_'$R$ & $R \times R \rightarrow R$ & $z = \min(x,y)$ & $+\infty$ & $-\infty$ \\ +\verb'GrB_MAX_'$R$ & $R \times R \rightarrow R$ & $z = \max(x,y)$ & $-\infty$ & $+\infty$ \\ +\hline % bool x bool -> bool \verb'GrB_LOR' & \verb'bool' $\times$ \verb'bool' $\rightarrow$ \verb'bool' & $z = x \vee y $ & false & true \\ \verb'GrB_LAND' & \verb'bool' $\times$ \verb'bool' $\rightarrow$ \verb'bool' & $z = x \wedge y $ & true & false \\ \verb'GrB_LXOR' & \verb'bool' $\times$ \verb'bool' $\rightarrow$ \verb'bool' & $z = x \veebar y $ & false & none \\ -\verb'GrB_EQ_BOOL' & \verb'bool' $\times$ \verb'bool' $\rightarrow$ \verb'bool' & $z =(x == y)$ & true & none \\ +\verb'GrB_LXNOR' & \verb'bool' $\times$ \verb'bool' $\rightarrow$ \verb'bool' & $z =(x == y)$ & true & none \\ +\hline +% bitwise +\verb'GrB_BOR_'$I$ & $I$ $\times$ $I$ $\rightarrow$ $I$ & \verb'z=x|y' & all bits zero & all bits one \\ +\verb'GrB_BAND_'$I$ & $I$ $\times$ $I$ $\rightarrow$ $I$ & \verb'z=x&y' & all bits one & all bits zero \\ +\verb'GrB_BXOR_'$I$ & $I$ $\times$ $I$ $\rightarrow$ $I$ & \verb'z=x^y' & all bits zero & none \\ +\verb'GrB_BXNOR_'$I$ & $I$ $\times$ $I$ $\rightarrow$ $I$ & \verb'z=~(x^y)' & all bits one & none \\ \hline \end{tabular} } @@ -2584,13 +2819,26 @@ \subsection{GraphBLAS monoids: {\sf GrB\_Monoid}} %============================= \verb'NaN'. Technically, their terminal value is \verb'NaN', but this value is rare in practice and thus the terminal condition is not worth checking. -SuiteSparse:GraphBLAS predefines each of the 55 unique monoids that can be -constructed with built-in types and operators, with the naming convention -\verb'GxB_op_type_MONOID'. For the first 50, \verb'op' is \verb'MIN', -\verb'MAX', \verb'PLUS', \verb'TIMES', or \verb'ANY', and \verb'type' is all -but \verb'BOOL'. The five Boolean monoids are \verb'GxB_LOR_BOOL_MONOID', -\verb'GxB_LAND_BOOL_MONOID', \verb'GxB_LXOR_BOOL_MONOID', -\verb'GxB_EQ_BOOL_MONOID', and \verb'GxB_ANY_BOOL_MONOID'. +% 40: (min,max,+,*) x (int8,16,32,64, uint8,16,32,64, fp32, fp64) +The C API Specification includes 44 predefined monoids, with the naming +convention \verb'GrB_op_MONOID_type'. Forty monoids are available for the four +operators \verb'MIN', \verb'MAX', \verb'PLUS', and \verb'TIMES', each with the +10 non-boolean real types. Four boolean monoids are predefined: +\verb'GrB_LOR_MONOID_BOOL', \verb'GrB_LAND_MONOID_BOOL', +\verb'GrB_LXOR_MONOID_BOOL', and \verb'GrB_LXNOR_MONOID_BOOL'. + +% 13 ANY +% 4 complex (PLUS, TIMES) +% 16 bitwise +% 33 total +These all appear in SuiteSparse:GraphBLAS, which adds 33 additional predefined +\verb'GxB*' monoids, with the naming convention \verb'GxB_op_type_MONOID'. The +\verb'ANY' operator can be used for all 13 types (including complex). The +\verb'PLUS' and \verb'TIMES' operators are provided for both complex types, for +4 additional complex monoids. Sixteen monoids are predefined for four bitwise +operators (\verb'BOR', \verb'BAND', \verb'BXOR', and \verb'BNXOR'), each with +four unsigned integer types (\verb'UINT8', \verb'UINT16', \verb'UINT32', and +\verb'UINT64'). The next sections define the following methods for the \verb'GrB_Monoid' object: @@ -2599,7 +2847,8 @@ \subsection{GraphBLAS monoids: {\sf GrB\_Monoid}} %============================= {\footnotesize \begin{tabular}{ll} \hline -\verb'GrB_Monoid_new' & create a monoid \\ +\verb'GrB_Monoid_new' & create a user-defined monoid \\ +\verb'GrB_Monoid_wait' & wait for a user-defined monoid \\ \verb'GxB_Monoid_terminal_new' & create a monoid that has a terminal value\\ \verb'GxB_Monoid_operator' & return the monoid operator \\ \verb'GxB_Monoid_identity' & return the monoid identity value \\ @@ -2611,7 +2860,7 @@ \subsection{GraphBLAS monoids: {\sf GrB\_Monoid}} %============================= \vspace{0.2in} \begin{spec} -{\bf SPEC:} The predefined monoids are an extension to the spec. +{\bf SPEC:} The predefined \verb'GxB*' monoids are an extension to the spec. \end{spec} \newpage @@ -2648,7 +2897,27 @@ \subsubsection{{\sf GrB\_Monoid\_new:} create a monoid} \verb'identity' parameter is ignored, and its known identity value is used instead. -% \newpage +%------------------------------------------------------------------------------- +\subsubsection{{\sf GrB\_Monoid\_wait:} wait for a monoid} +%------------------------------------------------------------------------------- + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_Monoid_wait // wait for a user-defined monoid +( + GrB_Monoid *monoid // monoid to wait for +) ; +\end{verbatim} +}\end{mdframed} + +After creating a user-defined monoid, a GraphBLAS library may choose to exploit +non-blocking mode to delay its creation. \verb'GrB_Monoid_wait(&monoid)' +ensures the \verb'monoid' is completed. SuiteSparse:GraphBLAS currently does +nothing for \verb'GrB_Monoid_wait(&monoid)', except to ensure that the +\verb'monoid' is valid. + +\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_Monoid\_terminal\_new:} create a monoid with terminal} %------------------------------------------------------------------------------- @@ -2838,16 +3107,16 @@ \subsection{GraphBLAS semirings: {\sf GrB\_Semiring}} %========================= multiplication of two sparse matrices in GraphBLAS, ${\bf C=AB}$. The ``add'' operator is a commutative and associative monoid, and the binary ``multiply'' operator defines a function $z=fmult(x,y)$ where the type of $z$ matches the -exactly with the monoid type. SuiteSparse:GraphBLAS includes 1355 -predefined built-in semirings, which are all those that can be constructed -from built-in types and operators. The next sections define the following -methods for the \verb'GrB_Semiring' object: +exactly with the monoid type. SuiteSparse:GraphBLAS includes 1,473 predefined +built-in semirings. The next sections define the following methods for the +\verb'GrB_Semiring' object: \vspace{0.2in} {\footnotesize \begin{tabular}{ll} \hline -\verb'GrB_Semiring_new' & create a semiring \\ +\verb'GrB_Semiring_new' & create a user-defined semiring \\ +\verb'GrB_Semiring_wait' & wait for a user-defined semiring \\ \verb'GxB_Semiring_add' & return the additive monoid of a semiring \\ \verb'GxB_Semiring_multiply' & return the binary operator of a semiring \\ \verb'GrB_Semiring_free' & free a semiring \\ @@ -2878,15 +3147,36 @@ \subsubsection{{\sf GrB\_Semiring\_new:} create a semiring} addition to the standard error cases, the function returns \verb'GrB_DOMAIN_MISMATCH' if the output (\verb'ztype') domain of \verb'multiply' does not match the domain of the \verb'add' monoid. Using -built-in types and operators, 1355 semirings can be built. This count +built-in types and operators, 2,438 semirings can be built. This count excludes redundant Boolean operators (for example \verb'GrB_TIMES_BOOL' and \verb'GrB_LAND' are different operators but they are redundant since they always return the same result). +The v1.3 C API Specification for GraphBLAS includes 124 predefined semirings, +with names of the form \verb'GrB_add_mult_SEMIRING_type', where \verb'add' is +the operator of the additive monoid, \verb'mult' is the multiply operator, and +\verb'type' is the type of the input $x$ to the multiply operator, $f(x,y)$. +The name of the domain for the additive monoid does not appear in the name, +since it always matches the type of the output of the \verb'mult' operator. + +Twelve kinds of \verb'GrB*' semirings are available for all 10 real, non-boolean types: + \verb'PLUS_TIMES', \verb'PLUS_MIN', + \verb'MIN_PLUS', \verb'MIN_TIMES', \verb'MIN_FIRST', \verb'MIN_SECOND', \verb'MIN_MAX', + \verb'MAX_PLUS', \verb'MAX_TIMES', \verb'MAX_FIRST', \verb'MAX_SECOND', and \verb'MAX_MIN'. +Four semirings are for boolean types only: + \verb'LOR_LAND', \verb'LAND_LOR', \verb'LXOR_LAND', and \verb'LXNOR_LOR'. + +SuiteSparse:GraphBLAS pre-defines 1,473 of the 2,438 unique semirings that can +be constructed from built-in types and operators, listed below, as an extension +to the spec. The naming convention is \verb'GxB_add_mult_type'. The 124 +\verb'GrB*' semirings are a subset of the list below, included with two names: +\verb'GrB*' and \verb'GxB*'. If the \verb'GrB*' name is provided, its use is +preferred, for portability to other GraphBLAS implementations. + \vspace{-0.05in} \begin{itemize} \item 1000 semirings with a multiplier $T \times T \rightarrow T$ where $T$ is - non-Boolean, from the complete cross product of: + any of the 10 non-Boolean, real types, from the complete cross product of: \vspace{-0.05in} \begin{itemize} @@ -2901,7 +3191,7 @@ \subsubsection{{\sf GrB\_Semiring\_new:} create a semiring} \end{itemize} \item 300 semirings with a comparison operator $T \times T \rightarrow$ - \verb'bool', where $T$ is non-Boolean, from the complete cross product of: + \verb'bool', where $T$ is non-Boolean and real, from the complete cross product of: \vspace{-0.05in} \begin{itemize} @@ -2924,24 +3214,56 @@ \subsubsection{{\sf GrB\_Semiring\_new:} create a semiring} \verb'EQ', \verb'GT', \verb'LT', \verb'GE', \verb'LE') \end{itemize} -\end{itemize} +\item 54 complex semirings, $Z \times Z \rightarrow Z$ where $Z$ is + \verb'GxB_FC32' (single precision complex) or + \verb'GxB_FC64' (double precision complex): -\vspace{-0.05in} -SuiteSparse:GraphBLAS pre-defines all 1355 unique semirings that can be -constructed from built-in types and operators, as an extension to the spec. -The naming convention is \verb'GxB_add_mult_type', where \verb'add' is the -operator of the additive monoid, \verb'mult' is the multiply operator, and -\verb'type' is the type of inputs to the multiply operator. The name of the -domain for the additive monoid does not appear, since it always matches the -type of the output of the \verb'mult' operator. For example -\verb'GxB_LAND_EQ_FP32' uses the \verb'GxB_LAND_BOOL_MONOID' as its additive -monoid, and the \verb'GrB_EQ_FP32' as the binary multiplicative operator. + \vspace{-0.05in} + \begin{itemize} + \item 3 complex monoids (\verb'PLUS', \verb'TIMES', \verb'ANY') + \item 9 complex multiply operators: + (\verb'FIRST', \verb'SECOND', \verb'PAIR', \verb'PLUS', \verb'MINUS', + \verb'TIMES', \verb'DIV', \verb'RDIV', \verb'RMINUS') + \item 2 complex types, $Z$ + \end{itemize} + +\item 64 bitwise semirings, $U \times U \rightarrow U$ where $U$ is + an unsigned integer. + + \vspace{-0.05in} + \begin{itemize} + \item 4 bitwise monoids (\verb'BOR', \verb'BAND', \verb'BXOR', \verb'BXNOR') + \item 4 bitwise multiply operators (the same list) + \item 4 unsigned integer types + \end{itemize} + +\end{itemize} \begin{spec} -{\bf SPEC:} Predefined semirings are an extension to the spec. +{\bf SPEC:} Predefined \verb'GxB*' semirings are an extension to the spec. \end{spec} -\newpage +%------------------------------------------------------------------------------- +\subsubsection{{\sf GrB\_Semiring\_wait:} wait for a semiring} +%------------------------------------------------------------------------------- + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_Semiring_wait // wait for a user-defined semiring +( + GrB_Semiring *semiring // semiring to wait for +) ; +\end{verbatim} +}\end{mdframed} + +After creating a user-defined semiring, a GraphBLAS library may choose to +exploit non-blocking mode to delay its creation. +\verb'GrB_Semiring_wait(&semiring)' ensures the \verb'semiring' is completed. +SuiteSparse:GraphBLAS currently does nothing for +\verb'GrB_Semiring_wait(&semiring)', except to ensure that the \verb'semiring' +is valid. + %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_Semiring\_add:} return the additive monoid of a semiring} %------------------------------------------------------------------------------- @@ -2964,7 +3286,7 @@ \subsubsection{{\sf GxB\_Semiring\_add:} return the additive monoid of a semirin {\bf SPEC:} \verb'GxB_Semiring_add' is an extension to the spec. \end{spec} -% \newpage +\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_Semiring\_multiply:} return multiply operator of a semiring} %------------------------------------------------------------------------------- @@ -3034,6 +3356,7 @@ \subsection{GraphBLAS scalars: {\sf GxB\_Scalar}} %============================= \begin{tabular}{ll} \hline \verb'GxB_Scalar_new' & create a sparse scalar \\ +\verb'GxB_Scalar_wait' & wait for a scalar \\ \verb'GxB_Scalar_dup' & copy a sparse scalar \\ \verb'GxB_Scalar_clear' & clear a sparse scalar of its entry \\ \verb'GxB_Scalar_nvals' & return the number of entries in a @@ -3067,6 +3390,26 @@ \subsubsection{{\sf GxB\_Scalar\_new:} create a sparse scalar} \verb's = sparse (0)', except that GraphBLAS can create sparse scalars any type. The pattern of the new scalar is empty. +%------------------------------------------------------------------------------- +\subsubsection{{\sf GxB\_Scalar\_wait:} wait for a scalar} +%------------------------------------------------------------------------------- + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GxB_Scalar_wait // wait for a scalar +( + GxB_Scalar *s // scalar to wait for +) ; +\end{verbatim} +}\end{mdframed} + +In non-blocking mode, the computations for a \verb'GxB_Scalar' may be delayed. +In this case, the scalar is not yet safe to use by multiple independent user +threads. A user application may force completion of a scalar \verb's' via +\verb'GxB_Scalar_wait(&s)'. After this call, different user threads may safely +call GraphBLAS operations that use the scalar \verb's' as an input parameter. + \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_Scalar\_dup:} copy a sparse scalar} @@ -3126,8 +3469,7 @@ \subsubsection{{\sf GxB\_Scalar\_clear:} clear a sparse scalar of its entry} \verb'GxB_Scalar_clear' clears the entry from a sparse scalar. The pattern of \verb's' is empty, just as if it were created fresh with \verb'GxB_Scalar_new'. Analogous with \verb's = sparse (0)' in MATLAB. The type of \verb's' does not -change. In SuiteSparse:GraphBLAS, any pending updates to the sparse scalar are -discarded. +change. Any pending updates to the sparse scalar are discarded. \newpage %------------------------------------------------------------------------------- @@ -3152,12 +3494,6 @@ \subsubsection{{\sf GxB\_Scalar\_nvals:} return the number of entries in a spars ``number of nonzeros'') in MATLAB is better described as ``number of entries'' in GraphBLAS. -\paragraph{Forced completion:} -All computations for the sparse scalar \verb's' are guaranteed to be finished -when \verb'GxB_Scalar_nvals' method returns. See the discussion about -\verb'GxB_Vector_nvals' in Section~\ref{vector_nvals} for more details. - -% \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_Scalar\_type:} return the type of a sparse scalar} %------------------------------------------------------------------------------- @@ -3177,7 +3513,6 @@ \subsubsection{{\sf GxB\_Scalar\_type:} return the type of a sparse scalar} \verb'GxB_Scalar_type' returns the type of a sparse scalar. Analogous to \verb'type = class (s)' in MATLAB. -% \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_Scalar\_setElement:} set the single entry of a sparse scalar} %------------------------------------------------------------------------------- @@ -3197,6 +3532,7 @@ \subsubsection{{\sf GxB\_Scalar\_setElement:} set the single entry of a sparse s \verb's = sparse(x)' in MATLAB notation. For further details of this function, see \verb'GxB_Matrix_setElement' in Section~\ref{matrix_setElement}. +\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_Scalar\_extractElement:} get the single entry from a sparse scalar} %------------------------------------------------------------------------------- @@ -3219,11 +3555,6 @@ \subsubsection{{\sf GxB\_Scalar\_extractElement:} get the single entry from a sp sparse scalar \verb's', then \verb'x' is not modified, and the return value of \verb'GxB_Scalar_extractElement' is \verb'GrB_NO_VALUE'. -\paragraph{Forced completion:} -All computations for the sparse scalar \verb's' are -guaranteed to be finished when the method returns. - -% \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_Scalar\_free:} free a sparse scalar} %------------------------------------------------------------------------------- @@ -3249,8 +3580,7 @@ \subsubsection{{\sf GxB\_Scalar\_free:} free a sparse scalar} \noindent frees the sparse scalar \verb's' and sets \verb's' to \verb'NULL'. It safely does nothing if passed a \verb'NULL' handle, or if \verb's == NULL' on input. -In SuiteSparse:GraphBLAS, any pending updates to the sparse scalar are -abandoned. +Any pending updates to the sparse scalar are abandoned. \newpage %=============================================================================== @@ -3289,6 +3619,7 @@ \subsection{GraphBLAS vectors: {\sf GrB\_Vector}} %============================= \begin{tabular}{ll} \hline \verb'GrB_Vector_new' & create a vector \\ +\verb'GrB_Vector_wait' & wait for a vector \\ \verb'GrB_Vector_dup' & copy a vector \\ \verb'GrB_Vector_clear' & clear a vector of all entries \\ \verb'GrB_Vector_size' & return the size of a vector \\ @@ -3297,8 +3628,9 @@ \subsection{GraphBLAS vectors: {\sf GrB\_Vector}} %============================= \verb'GrB_Vector_build' & build a vector from a set of tuples \\ \verb'GrB_Vector_setElement' & add a single entry to a vector \\ \verb'GrB_Vector_extractElement' & get a single entry from a vector \\ +\verb'GrB_Vector_removeElement' & remove a single entry from a vector \\ \verb'GrB_Vector_extractTuples' & get all entries from a vector \\ -\verb'GxB_Vector_resize' & resize a vector \\ +\verb'GrB_Vector_resize' & resize a vector \\ \verb'GrB_Vector_free' & free a vector \\ \hline \verb'GxB_Vector_import' & import a vector @@ -3333,6 +3665,26 @@ \subsubsection{{\sf GrB\_Vector\_new:} create a vector} \verb'v = sparse (n,1)', except that GraphBLAS can create sparse vectors any type. The pattern of the new vector is empty. +%------------------------------------------------------------------------------- +\subsubsection{{\sf GrB\_Vector\_wait:} wait for a vector} +%------------------------------------------------------------------------------- + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_Vector_wait // wait for a vector +( + GrB_Vector *w // vector to wait for +) ; +\end{verbatim} +}\end{mdframed} + +In non-blocking mode, the computations for a \verb'GrB_Vector' may be delayed. +In this case, the vector is not yet safe to use by multiple independent user +threads. A user application may force completion of a vector \verb'w' via +\verb'GrB_Vector_wait(&w)'. After this call, different user threads may safely +call GraphBLAS operations that use the vector \verb'w' as an input parameter. + % \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Vector\_dup:} copy a vector} @@ -3374,7 +3726,6 @@ \subsubsection{{\sf GrB\_Vector\_dup:} copy a vector} same set of values, but they do not depend on each other. Modifying one has no effect on the other. -\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Vector\_clear:} clear a vector of all entries} %------------------------------------------------------------------------------- @@ -3394,11 +3745,9 @@ \subsubsection{{\sf GrB\_Vector\_clear:} clear a vector of all entries} \verb'v(i)' are now equal to the implicit value, depending on what semiring ring is used to perform computations on the vector. The pattern of \verb'v' is empty, just as if it were created fresh with \verb'GrB_Vector_new'. Analogous -with \verb'v (:) = 0' in MATLAB. The type and dimension of \verb'v' do not -change. In SuiteSparse:GraphBLAS, any pending updates to the vector are -discarded. +with \verb'v (:) = sparse(0)' in MATLAB. The type and dimension of \verb'v' do +not change. Any pending updates to the vector are discarded. -% \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Vector\_size:} return the size of a vector} %------------------------------------------------------------------------------- @@ -3440,23 +3789,6 @@ \subsubsection{{\sf GrB\_Vector\_nvals:} return the number of entries in GraphBLAS need not be zero and \verb'nnz' (short for ``number of nonzeros'') in MATLAB is better described as ``number of entries'' in GraphBLAS. -\paragraph{Forced completion:} -All computations for the vector \verb'v' are guaranteed to be finished when -\verb'GrB_Vector_nvals' method returns. -% -That is, it acts like an object-specific \verb'GrB_wait' for just this -particular vector \verb'v', which is a side-effect useful in its own right. -For example, suppose the computations required for \verb'v' rely upon a -user-defined operator that accesses a user-controlled global variable outside -the scope or control of GraphBLAS. If the user-application needs to modify or -free the variable, \verb'GrB_Vector_nvals' can be used to force all pending -operations for this vector \verb'v' to complete. The user application can then -safely modify the global variable. A call to \verb'GrB_Vector_nvals(&nvals,v)' -only ensures that the computations require to compute \verb'v' are finished; -other pending computations for other objects may remain. To ensure that all -pending computations are complete for all GraphBLAS objects, use -\verb'GrB_wait' instead. - % \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_Vector\_type:} return the type of a vector} @@ -3481,7 +3813,6 @@ \subsubsection{{\sf GxB\_Vector\_type:} return the type of a vector} {\bf SPEC:} \verb'GxB_Vector_type' is an extension to the spec. \end{spec} -\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Vector\_build:} build a vector from a set of tuples} %------------------------------------------------------------------------------- @@ -3517,7 +3848,6 @@ \subsubsection{{\sf GrB\_Vector\_build:} build a vector from a set of tu {\bf SPEC:} As an extension to the spec, results are defined even if \verb'dup' is non-associative. \end{spec} -% \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Vector\_setElement:} add a single entry to a vector} %------------------------------------------------------------------------------- @@ -3530,7 +3860,7 @@ \subsubsection{{\sf GrB\_Vector\_setElement:} add a single entry to a vector} ( GrB_Vector w, // vector to modify x, // scalar to assign to w(i) - GrB_Index i // row index + GrB_Index i // index ) ; \end{verbatim} } \end{mdframed} @@ -3540,7 +3870,6 @@ \subsubsection{{\sf GrB\_Vector\_setElement:} add a single entry to a vector} \verb'j=0'. For further details of this function, see \verb'GrB_Matrix_setElement' in Section~\ref{matrix_setElement}. -\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Vector\_extractElement:} get a single entry from a vector} %------------------------------------------------------------------------------- @@ -3553,7 +3882,7 @@ \subsubsection{{\sf GrB\_Vector\_extractElement:} get a single entry from a vect ( *x, // scalar extracted const GrB_Vector v, // vector to extract an entry from - GrB_Index i // row index + GrB_Index i // index ) ; \end{verbatim} } \end{mdframed} @@ -3567,11 +3896,24 @@ \subsubsection{{\sf GrB\_Vector\_extractElement:} get a single entry from a vect \verb'x' is not modified, and the return value of \verb'GrB_Vector_extractElement' is \verb'GrB_NO_VALUE'. -\paragraph{Forced completion:} -All computations for the vector \verb'v' are -guaranteed to be finished when the method returns. +%------------------------------------------------------------------------------- +\subsubsection{{\sf GrB\_Vector\_removeElement:} remove a single entry from a vector} +%------------------------------------------------------------------------------- +\label{vector_removeElement} + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_Vector_removeElement +( + GrB_Vector v, // vector to remove an entry from + GrB_Index i // index +) ; +\end{verbatim} } \end{mdframed} + +\verb'GrB_Vector_removeElement' removes a single entry \verb'v(i)' from a vector. +If no entry is present at \verb'v(i)', then the vector is not modified. -% \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Vector\_extractTuples:} get all entries from a vector} %------------------------------------------------------------------------------- @@ -3596,30 +3938,25 @@ \subsubsection{{\sf GrB\_Vector\_extractTuples:} get all entries from a vector} Section~\ref{matrix_extractTuples} where further details of this function are described. -\paragraph{Forced completion:} -All computations for the vector \verb'v' are -guaranteed to be finished when the method returns. - -\newpage %------------------------------------------------------------------------------- -\subsubsection{{\sf GxB\_Vector\_resize:} resize a vector} +\subsubsection{{\sf GrB\_Vector\_resize:} resize a vector} %------------------------------------------------------------------------------- \label{vector_resize} \begin{mdframed}[userdefinedwidth=6in] {\footnotesize \begin{verbatim} -GrB_Info GxB_Vector_resize // change the size of a vector +GrB_Info GrB_Vector_resize // change the size of a vector ( GrB_Vector u, // vector to modify GrB_Index nrows_new // new number of rows in vector ) ; \end{verbatim} } \end{mdframed} -\verb'GxB_Vector_resize' changes the size of a vector. If the dimension +\verb'GrB_Vector_resize' changes the size of a vector. If the dimension decreases, entries that fall outside the resized vector are deleted. -% \newpage +\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Vector\_free:} free a vector} %------------------------------------------------------------------------------- @@ -3644,8 +3981,8 @@ \subsubsection{{\sf GrB\_Vector\_free:} free a vector} \noindent frees the vector \verb'v' and sets \verb'v' to \verb'NULL'. It safely does -nothing if passed a \verb'NULL' handle, or if \verb'v == NULL' on input. -In SuiteSparse:GraphBLAS, any pending updates to the vector are abandoned. +nothing if passed a \verb'NULL' handle, or if \verb'v == NULL' on input. Any +pending updates to the vector are abandoned. \newpage %=============================================================================== @@ -3661,6 +3998,7 @@ \subsection{GraphBLAS matrices: {\sf GrB\_Matrix}} %============================ \begin{tabular}{ll} \hline \verb'GrB_Matrix_new' & create a matrix \\ +\verb'GrB_Matrix_wait' & wait for a matrix \\ \verb'GrB_Matrix_dup' & copy a matrix \\ \verb'GrB_Matrix_clear' & clear a matrix of all entries \\ \verb'GrB_Matrix_nrows' & return the number of rows of a matrix \\ @@ -3670,8 +4008,9 @@ \subsection{GraphBLAS matrices: {\sf GrB\_Matrix}} %============================ \verb'GrB_Matrix_build' & build a matrix from a set of tuples \\ \verb'GrB_Matrix_setElement' & add a single entry to a matrix \\ \verb'GrB_Matrix_extractElement'& get a single entry from a matrix \\ +\verb'GrB_Matrix_removeElement' & remove a single entry from a matrix \\ \verb'GrB_Matrix_extractTuples' & get all entries from a matrix \\ -\verb'GxB_Matrix_resize' & resize a matrix \\ +\verb'GrB_Matrix_resize' & resize a matrix \\ \verb'GrB_Matrix_free' & free a matrix \\ \hline \verb'GxB_Matrix_import_CSR' & import a matrix in CSR form @@ -3718,6 +4057,28 @@ \subsubsection{{\sf GrB\_Matrix\_new:} create a matrix} statement \verb'A = sparse (nrows, ncols)', except that GraphBLAS can create sparse matrices of any type. +%------------------------------------------------------------------------------- +\subsubsection{{\sf GrB\_Matrix\_wait:} wait for a matrix} +%------------------------------------------------------------------------------- + +% GB_PUBLIC GrB_Info GrB_Descriptor_wait (GrB_Descriptor *desc ) ; + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_Matrix_wait // wait for a matrix +( + GrB_Matrix *C // matrix to wait for +) ; +\end{verbatim} +}\end{mdframed} + +In non-blocking mode, the computations for a \verb'GrB_Matrix' may be delayed. +In this case, the matrix is not yet safe to use by multiple independent user +threads. A user application may force completion of a matrix \verb'C' via +\verb'GrB_Matrix_wait(&C)'. After this call, different user threads may safely +call GraphBLAS operations that use the matrix \verb'C' as an input parameter. + % \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Matrix\_dup:} copy a matrix} @@ -3758,7 +4119,7 @@ \subsubsection{{\sf GrB\_Matrix\_dup:} copy a matrix} same set of values, but they do not depend on each other. Modifying one has no effect on the other. -% \newpage +\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Matrix\_clear:} clear a matrix of all entries} %------------------------------------------------------------------------------- @@ -3778,8 +4139,7 @@ \subsubsection{{\sf GrB\_Matrix\_clear:} clear a matrix of all entries} ring is used to perform computations on the matrix. The pattern of \verb'A' is empty, just as if it were created fresh with \verb'GrB_Matrix_new'. Analogous with \verb'A (:,:) = 0' in MATLAB. The type and dimensions of \verb'A' do not -change. In SuiteSparse:Graph\-BLAS, any pending updates to the matrix are -discarded. +change. Any pending updates to the matrix are discarded. % \newpage %------------------------------------------------------------------------------- @@ -3820,7 +4180,7 @@ \subsubsection{{\sf GrB\_Matrix\_ncols:} return the number of columns of \verb'GrB_Matrix_ncols' returns the number of columns of a matrix (\verb'ncols=size(A,2)' in MATLAB). -% \newpage +\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Matrix\_nvals:} return the number of entries in a matrix} %------------------------------------------------------------------------------- @@ -3841,15 +4201,6 @@ \subsubsection{{\sf GrB\_Matrix\_nvals:} return the number of entries in GraphBLAS need not be zero and \verb'nnz' (short for ``number of nonzeros'') in MATLAB is better described as ``number of entries'' in GraphBLAS. -\paragraph{Forced completion:} -All computations for the matrix \verb'A' are guaranteed to be finished when -\verb'GrB_Matrix_nvals' returns. That is, it acts like an object-specific -\verb'GrB_wait' for just this particular matrix \verb'A'. Other pending -computations for other objects may remain. To ensure that all pending -computations are complete for all GraphBLAS objects, used \verb'GrB_wait' -instead. - -\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_Matrix\_type:} return the type of a matrix} %------------------------------------------------------------------------------- @@ -3860,6 +4211,7 @@ \subsubsection{{\sf GxB\_Matrix\_type:} return the type of a matrix} \begin{verbatim} GrB_Info GxB_Matrix_type // get the type of a matrix ( +\newpage GrB_Type *type, // returns the type of the matrix const GrB_Matrix A // matrix to query ) ; @@ -3872,7 +4224,6 @@ \subsubsection{{\sf GxB\_Matrix\_type:} return the type of a matrix} {\bf SPEC:} \verb'GxB_Matrix_type' is an extension to the spec. \end{spec} -\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Matrix\_build:} build a matrix from a set of tuples} %------------------------------------------------------------------------------- @@ -3972,7 +4323,6 @@ \subsubsection{{\sf GrB\_Matrix\_build:} build a matrix from a set of tuples} for assembling duplicates (summation), and it can only build double, double complex, and logical sparse matrices. -\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Matrix\_setElement:} add a single entry to a matrix} %------------------------------------------------------------------------------- @@ -4023,7 +4373,8 @@ \subsubsection{{\sf GrB\_Matrix\_setElement:} add a single entry to a matrix} once, using the same algorithm used for \verb'GrB_Matrix_build'. In other words, \verb'setElement' in SuiteSparse:GraphBLAS builds its own internal list of tuples \verb'[I,J,X]', and then calls \verb'GrB_Matrix_build' whenever the -matrix is needed in another computation, or whenever \verb'GrB_wait' is called. +matrix is needed in another computation, or whenever \verb'GrB_Matrix_wait' is +called. As a result, if calls to \verb'setElement' are mixed with calls to most other methods and operations (even \verb'extractElement') then the pending updates @@ -4034,7 +4385,7 @@ \subsubsection{{\sf GrB\_Matrix\_setElement:} add a single entry to a matrix} A few methods and operations can be intermixed with \verb'setElement', in particular, some forms of the \verb'GrB_assign' and \verb'GxB_subassign' operations are compatible with the pending updates from \verb'setElement'. -Sections~\ref{compare_assign} gives more details on which \verb'GxB_subassign' +Section~\ref{compare_assign} gives more details on which \verb'GxB_subassign' and \verb'GrB_assign' operations can be interleaved with calls to \verb'setElement' without forcing updates to be assembled. Other methods that do not access the existing entries may also be done without forcing the updates @@ -4096,17 +4447,32 @@ \subsubsection{{\sf GrB\_Matrix\_extractElement:} get a single entry from a matr \verb'x' must be a \verb'void *' pointer that points to a memory space the same size as a single scalar of the type of \verb'A'. -\paragraph{Forced completion:} -All computations for the matrix \verb'A' are -guaranteed to be finished when the method returns. -% -In particular, this method causes all pending updates from +Currently, this method causes all pending updates from \verb'GrB_setElement', \verb'GrB_assign', or \verb'GxB_subassign' to be assembled, so its use can have performance implications. Calls to this function should not be arbitrarily intermixed with calls to these other two functions. Everything will work correctly and results will be predictable, it will just be slow. +%------------------------------------------------------------------------------- +\subsubsection{{\sf GrB\_Matrix\_removeElement:} remove a single entry from a matrix} +%------------------------------------------------------------------------------- +\label{matrix_removeElement} + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_Matrix_removeElement +( + GrB_Matrix C, // matrix to remove an entry from + GrB_Index i, // row index + GrB_Index j // column index +) ; +\end{verbatim} } \end{mdframed} + +\verb'GrB_Matrix_removeElement' removes a single entry \verb'A(i,j)' from a matrix. +If no entry is present at \verb'A(i,j)', then the matrix is not modified. + % \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Matrix\_extractTuples:} get all entries from a matrix} @@ -4145,20 +4511,16 @@ \subsubsection{{\sf GrB\_Matrix\_extractTuples:} get all entries from a matrix} left unchanged. On output, \verb'nvals' contains the number of tuples extracted. -\paragraph{Forced completion:} -All computations for the matrix \verb'A' are -guaranteed to be finished when the method returns. - % \newpage %------------------------------------------------------------------------------- -\subsubsection{{\sf GxB\_Matrix\_resize:} resize a matrix} +\subsubsection{{\sf GrB\_Matrix\_resize:} resize a matrix} %------------------------------------------------------------------------------- \label{matrix_resize} \begin{mdframed}[userdefinedwidth=6in] {\footnotesize \begin{verbatim} -GrB_Info GxB_Matrix_resize // change the size of a matrix +GrB_Info GrB_Matrix_resize // change the size of a matrix ( GrB_Matrix A, // matrix to modify const GrB_Index nrows_new, // new number of rows in matrix @@ -4166,7 +4528,7 @@ \subsubsection{{\sf GxB\_Matrix\_resize:} resize a matrix} ) ; \end{verbatim} } \end{mdframed} -\verb'GxB_Matrix_resize' changes the size of a matrix. +\verb'GrB_Matrix_resize' changes the size of a matrix. If the dimensions decrease, entries that fall outside the resized matrix are deleted. @@ -4193,11 +4555,8 @@ \subsubsection{{\sf GrB\_Matrix\_free:} free a matrix} \noindent frees the matrix \verb'A' and sets \verb'A' to \verb'NULL'. It safely does -nothing if passed a \verb'NULL' handle, or if \verb'A == NULL' on input. -In SuiteSparse:GraphBLAS, any pending updates to the matrix are abandoned. - - - +nothing if passed a \verb'NULL' handle, or if \verb'A == NULL' on input. Any +pending updates to the matrix are abandoned. \newpage %=============================================================================== @@ -4259,8 +4618,10 @@ \subsection{GraphBLAS matrix and vector import/export} %======================== The vector import/export methods use a single format for a \verb'GrB_Vector'. Four different formats are provided for the import/export of a \verb'GrB_Matrix'. For each format, the \verb'Ax' array has a C type -corresponding to one of the 11 built-in types in GraphBLAS (\verb'bool', -\verb'int*_t', \verb'uint*_t', \verb'float', and \verb'double'), or that +corresponding to one of the 13 built-in types in GraphBLAS (\verb'bool', +\verb'int*_t', \verb'uint*_t', +\verb'float', \verb'double' +\verb'float complex', \verb'double complex'), or that corresponds with the user-defined type. No typecasting is done on import or export. @@ -5172,7 +5533,7 @@ \subsection{GraphBLAS descriptors: {\sf GrB\_Descriptor}} %===================== \newpage \begin{spec} -{\bf SPEC:} \verb'GxB_DEFAULT', \verb'GxB_NTHRADS', \verb'GxB_CHUNK', +{\bf SPEC:} \verb'GxB_DEFAULT', \verb'GxB_NTHREADS', \verb'GxB_CHUNK', \verb'GxB_AxB_METHOD', and \verb'GxB_AxB_*' are extensions to the spec. \end{spec} @@ -5248,12 +5609,12 @@ \subsection{GraphBLAS descriptors: {\sf GrB\_Descriptor}} %===================== \verb'desc [GrB_INP1]' is set to \verb'GrB_TRAN', then the second input, typically called \verb'B', is transposed. - Vectors are never transposed via the descriptor. If a method's first - parameter is a matrix and the second a vector, then \verb'desc [GrB_INP0]' - modifies the matrix parameter and \verb'desc [GrB_INP1]' is ignored. If a - method's first parameter is a vector and the second a matrix, then - \verb'desc [GrB_INP1]' modifies the matrix parameter and - \verb'desc [GrB_INP0]' is ignored. + Vectors and scalars are never transposed via the descriptor. If a method's + first parameter is a matrix and the second a vector or scalar, then + \verb'desc [GrB_INP0]' modifies the matrix parameter and + \verb'desc [GrB_INP1]' is ignored. If a method's first parameter is a + vector or scalar and the second a matrix, then \verb'desc [GrB_INP1]' + modifies the matrix parameter and \verb'desc [GrB_INP0]' is ignored. To clarify this in each function, the inputs are labeled as \verb'first input:' and \verb'second input:' in the function signatures. @@ -5285,20 +5646,9 @@ \subsection{GraphBLAS descriptors: {\sf GrB\_Descriptor}} %===================== {\em saxpy} operations, and using workspace of size $n$ per thread, corresponding to the number of columns of \verb'C'. - \item \verb'GxB_AxB_HEAP': - no longer appears in v3.2.0, but will likely - be reintroduced in a future version. This is silently replaced - with \verb'GxB_AxB_HASH'. - -% a heap-based method, computing -% \verb'C(:,j)=A*B(:,j)' via a heap of size equal to the maximum number of -% entries in any column of \verb'B'. The method is very good for hypersparse -% matrices, particularly when $|{\bf B}|$ is less than the number of rows of -% \verb'C'. The method used is similar to Algorithm II in -% \cite{BulucGilbert08} (see also \cite{BulucGilbert12}). It computes -% \verb'C' in the same order as Gustavson's method, using a heap instead of a -% large gather/scatter workspace. The heap has size $b$, equal to the -% maximum number of entries in any one vector of \verb'B'. + \item \verb'GxB_AxB_HEAP': no longer appears in SuiteSparse:GraphBLAS, but + may be reintroduced in a future version. This is silently replaced with + \verb'GxB_AxB_HASH'. \item \verb'GxB_AxB_HASH': a hash-based method, based on \cite{10.1145/3229710.3229720}. Very efficient for hypersparse @@ -5344,9 +5694,29 @@ \subsubsection{{\sf GrB\_Descriptor\_new:} create a new descriptor} \end{verbatim} } \end{mdframed} \verb'GrB_Descriptor_new' creates a new descriptor, with all fields set to -their defaults (output is not replaced, mask is not complemented, neither -input matrix is transposed, and the method used in \verb'C=A*B' is -selected automatically). +their defaults (output is not replaced, the mask is not complemented, the mask +is valued not structural, neither input matrix is transposed, and the method +used in \verb'C=A*B' is selected automatically). + +%------------------------------------------------------------------------------- +\subsubsection{{\sf GrB\_Descriptor\_wait:} wait for a descriptor} +%------------------------------------------------------------------------------- + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_Descriptor_wait // wait for a descriptor +( + GrB_Descriptor *descriptor // descriptor to wait for +) ; +\end{verbatim} +}\end{mdframed} + +After creating a user-defined descriptor, a GraphBLAS library may choose to +exploit non-blocking mode to delay its creation. +\verb'GrB_Descriptor_wait(&d)' ensures the descriptor \verb'd' is completed. +SuiteSparse:GraphBLAS currently does nothing for +\verb'GrB_Descriptor_wait(&d)', except to ensure that \verb'd' is valid. % \newpage %------------------------------------------------------------------------------- @@ -5458,13 +5828,10 @@ \subsubsection{{\sf GxB\_Desc\_set:} set a parameter in a descriptor} ) ; \end{verbatim} } \end{mdframed} -\verb'GxB_Desc_set' is identical to \verb'GrB_Descriptor_set', except that the -type of the third parameter can vary with the field. All descriptor fields are -currently of type \verb'GrB_Desc_Value', so currently this function is -identical in all ways to \verb'GrB_Descriptor_set', except for the name of the -function. Future versions of this function will allow for arbitrary types of -the third parameter, depending on the field. For a simpler-to-use alternative, -see \verb'GxB_set' described in Section~\ref{options}. +\verb'GxB_Desc_set' is like \verb'GrB_Descriptor_set', except that the +type of the third parameter can vary with the field. This function can +modify descriptor settings that do not have the type \verb'GrB_Desc_Value'. +See also \verb'GxB_set' described in Section~\ref{options}. \begin{spec} {\bf SPEC:} \verb'GxB_Desc_set' is an extension to the spec. @@ -5488,16 +5855,12 @@ \subsubsection{{\sf GxB\_Desc\_get:} get a parameter from a descriptor} \verb'GxB_Desc_get' returns the value of a single field in a descriptor. The type of the third parameter is a pointer to a variable type, whose type depends -on the field. Currently, all descriptor values are of type -\verb'GrB_Desc_Value', so this third parameter is a pointer to a scalar value of -type \verb'GrB_Desc_Value'. For a simpler-to-use alternative, see -\verb'GxB_get' described in Section~\ref{options}. +on the field. See also \verb'GxB_get' described in Section~\ref{options}. \begin{spec} {\bf SPEC:} \verb'GxB_Desc_get' is an extension to the spec. \end{spec} -\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Descriptor\_free:} free a descriptor} %------------------------------------------------------------------------------- @@ -5629,10 +5992,111 @@ \subsection{{\sf GrB\_free:} free any GraphBLAS object} %======================= Some objects are predefined, such as the built-in types. If a user application attempts to free a built-in object, SuiteSparse:GraphBLAS will safely do -nothing. In all cases, the \verb'GrB_free' function in SuiteSparse:GraphBLAS -always returns \verb'GrB_SUCCESS'. +nothing. The \verb'GrB_free' function in SuiteSparse:GraphBLAS returns +\verb'GrB_SUCCESS' or \verb'GrB_PANIC' in the unlikely event of a failure. +% TODO in 4.0: GrB_PANIC will not be returned. +\newpage +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{The mask, accumulator, and replace option} %%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\label{sec:maskaccum} + +After a GraphBLAS operation computes a result ${\bf T}$, (for example, ${\bf +T=AB}$ for \verb'GrB_mxm'), the results are assigned to an output matrix ${\bf +C}$ via the mask/ accumulator phase, written as ${\bf C \langle M \rangle = C +\odot T}$. This phase is affected by the \verb'GrB_REPLACE' option in the +descriptor, the presence of an optional binary accumulator operator ($\odot$), +the presence of the optional mask matrix ${\bf M}$, and the status of the mask +descriptor. The interplay of these options is summarized in +Table~\ref{tab:maskaccum}. + +The mask ${\bf M}$ may be present, or not. It may be structural or valued, and +it may be complemented, or not. These options may be combined, for a total of +8 cases, although the structural/valued option as no effect if ${\bf M}$ is not +present. If ${\bf M}$ is not present and not complemented, then $m_{ij}$ is +implicitly true. If not present yet complemeted, then all $m_{ij}$ entries are +implicitly zero; in this case, ${\bf T}$ need not be computed at all. Either +${\bf C}$ is not modified, or all its entries are cleared if the replace option +is enabled. If ${\bf M}$ is present, and the structural option is used, then +$m_{ij}$ is treated as true if it is an entry in the matrix (its value is +ignored). Otherwise, the value of $m_{ij}$ is used. In both cases, entries +not present are implicitly zero. These values are negated if the mask is +complemented. All of these various cases are combined to give a single +effective value of the mask at position ${ij}$. + +The combination of all these options are presented in the +Table~\ref{tab:maskaccum}. The first column is the \verb'GrB_REPLACE' option. +The second column lists whether or not the accumulator operator is present. +The third column lists whether or not $c_{ij}$ exists on input to the +mask/accumulator phase (a dash means that it does not exist). The fourth +column lists whether or not the entry $t_{ij}$ is present in the result matrix +${\bf T}$. The mask column is the final effective value of $m_{ij}$, after +accounting for the presence of ${\bf M}$ and the mask options. Finally, the +last column states the result of the mask/accum step; if no action is listed in +this column, then $c_{ij}$ is not modified. + +Several important observations can be made from this table. First, +if no mask is present (and the mask-complement descriptor option is not used), +then only the first half of the table is used. In this case, the \verb'GrB_REPLACE' +option has no effect. The entire matrix ${\bf C}$ is modified. + +Consider the cases when $c_{ij}$ is present but $t_{ij}$ is not, and there is no +mask or the effective value of the mask is true for this ${ij}$ position. With +no accumulator operator, $c_{ij}$ is deleted. If the accumulator operator is +present and the replace option is not used, $c_{ij}$ remains unchanged. +\begin{table} +{\small +\begin{tabular}{lllll|l} +\hline +repl & accum & ${\bf C}$ & ${\bf T}$ & mask & action taken by ${\bf C \langle M \rangle = C \odot T}$ \\ +\hline + - &- & $c_{ij}$ & $t_{ij}$ & 1 & $c_{ij} = t_{ij}$, update \\ + - &- & - & $t_{ij}$ & 1 & $c_{ij} = t_{ij}$, insert \\ + - &- & $c_{ij}$ & - & 1 & delete $c_{ij}$ because $t_{ij}$ not present \\ + - &- & - & - & 1 & \\ +\hline + yes&- & $c_{ij}$ & $t_{ij}$ & 1 & $c_{ij} = t_{ij}$, update \\ + yes&- & - & $t_{ij}$ & 1 & $c_{ij} = t_{ij}$, insert \\ + yes&- & $c_{ij}$ & - & 1 & delete $c_{ij}$ because $t_{ij}$ not present \\ + yes&- & - & - & 1 & \\ +\hline + - &yes & $c_{ij}$ & $t_{ij}$ & 1 & $c_{ij} = c_{ij} \odot t_{ij}$, apply accumulator \\ + - &yes & - & $t_{ij}$ & 1 & $c_{ij} = t_{ij}$, insert \\ + - &yes & $c_{ij}$ & - & 1 & \\ + - &yes & - & - & 1 & \\ +\hline + yes&yes & $c_{ij}$ & $t_{ij}$ & 1 & $c_{ij} = c_{ij} \odot t_{ij}$, apply accumulator \\ + yes&yes & - & $t_{ij}$ & 1 & $c_{ij} = t_{ij}$, insert \\ + yes&yes & $c_{ij}$ & - & 1 & \\ + yes&yes & - & - & 1 & \\ +\hline +\hline + - &- & $c_{ij}$ & $t_{ij}$ & 0 & \\ + - &- & - & $t_{ij}$ & 0 & \\ + - &- & $c_{ij}$ & - & 0 & \\ + - &- & - & - & 0 & \\ +\hline + yes&- & $c_{ij}$ & $t_{ij}$ & 0 & delete $c_{ij}$ (because of \verb'GrB_REPLACE') \\ + yes&- & - & $t_{ij}$ & 0 & \\ + yes&- & $c_{ij}$ & - & 0 & delete $c_{ij}$ (because of \verb'GrB_REPLACE') \\ + yes&- & - & - & 0 & \\ +\hline + - &yes & $c_{ij}$ & $t_{ij}$ & 0 & \\ + - &yes & - & $t_{ij}$ & 0 & \\ + - &yes & $c_{ij}$ & - & 0 & \\ + - &yes & - & - & 0 & \\ +\hline + yes&yes & $c_{ij}$ & $t_{ij}$ & 0 & delete $c_{ij}$ (because of \verb'GrB_REPLACE') \\ + yes&yes & - & $t_{ij}$ & 0 & \\ + yes&yes & $c_{ij}$ & - & 0 & delete $c_{ij}$ (because of \verb'GrB_REPLACE') \\ + yes&yes & - & - & 0 & \\ +\hline +\end{tabular} +} +\caption{Results of the mask/accumulator phase \label{tab:maskaccum}} +\end{table} \newpage @@ -5662,6 +6126,8 @@ \section{SuiteSparse:GraphBLAS Options} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% calling this function: by row, by column, and whether or not to use a {\em hypersparse} format \cite{BulucGilbert08,BulucGilbert12}. These are global options that modify all matrices created after calling this method. + The global settings also control the number of threads used, and the + heuristic for selecting the number of threads for small problems. \item \verb'GxB_set (GrB_Matrix A, field, value)' provides hints to SuiteSparse: GraphBLAS on how to store a particular matrix. This method @@ -5680,7 +6146,7 @@ \section{SuiteSparse:GraphBLAS Options} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{itemize} -\item \verb'GxB_get (field, &value)' retrieves the current value of +\item \verb'GxB_get (field, &value)' retrieves the value of a global option. \item \verb'GxB_get (GrB_Matrix A, field, &value)' retrieves the current @@ -5757,7 +6223,7 @@ \subsection{OpenMP parallelism} \verb'GxB_set (GxB_NTHREADS, 4)' is used, then the global setting is four threads, not eight. If a descriptor is used but its \verb'GxB_NTHREADS' is not set, or set to \verb'GxB_DEFAULT', then any operation that uses this descriptor - +will use 4 threads. %------------------------------------------------------------------------------- \subsection{Storing a matrix by row or by column} @@ -5905,7 +6371,7 @@ \subsection{Hypersparse matrices} A new matrix created via \verb'GrB_Matrix_new' starts with $k=0$ and is created in hypersparse form by default unless $n \le 1$ or if $h<0$, where $h$ is the -global \verb'hyper_ratio' value. The matrix is created in in either +global \verb'hyper_ratio' value. The matrix is created in either \verb'GxB_BY_ROW' or \verb'GxB_BY_COL' format, as determined by the last call to \verb'GxB_set(GxB_FORMAT,...)' or \verb'GrB_init'. @@ -6018,7 +6484,7 @@ \subsection{Hypersparse matrices} SuiteSparse:GraphBLAS will be silently ignored, so the use these options is safe for future updates. -The hypersparse status of a matrix can be queried with the following usage: +The hypersparse status of a matrix can be queried with the following: {\footnotesize \begin{verbatim} @@ -6055,14 +6521,13 @@ \subsection{Other global options} If multiple user threads make simultaneous calls to GraphBLAS, then output matrices and vectors used by different threads must be different, and input matrices and vectors can be safely used only if any pending computations on -them have finished, via \verb'GrB_wait' or the per-matrix methods, -\verb'GrB_*_nvals', \verb'GrB_*_extractElement', \verb'GrB_*_extractTuples', -and reduction to a scalar via \verb'GrB_*_reduce'. +them have finished, via \verb'GrB_Matrix_wait', \verb'GrB_Vector_wait', or +\verb'GxB_Scalar_wait'. The \verb'GxB_THREAD_SAFETY' option returns the threading model used internally -to synchronize user threads. This is determined during installation (see -Section~\ref{sec:threads}). Since \verb'GxB_THREAD_NONE' is zero, the -following can be used: +to synchronize user threads, solely for the now-deprecated \verb'GrB_wait()'. +This is determined during installation (see Section~\ref{sec:threads}). Since +\verb'GxB_THREAD_NONE' is zero, the following can be used: {\footnotesize \begin{verbatim} @@ -6160,15 +6625,15 @@ \subsection{{\sf GxB\_Matrix\_Option\_set:} set a matrix option} but since they are simply hints, future versions of SuiteSparse:GraphBLAS may delay the change in format if it can obtain better performance. -For performance, the matrix option should be set as soon as it is created with -\verb'GrB_Matrix_new', so the internal transformation takes less time. - {\footnotesize \begin{verbatim} GxB_set (A, GxB_HYPER, 0.2) ; GxB_set (A, GxB_FORMAT, GxB_BY_COL) ; \end{verbatim} } +For performance, the matrix option should be set as soon as it is created with +\verb'GrB_Matrix_new', so the internal transformation takes less time. + \newpage %=============================================================================== \subsection{{\sf GxB\_Desc\_set:} set a {\sf GrB\_Descriptor} value} @@ -6258,19 +6723,22 @@ \subsection{{\sf GxB\_Matrix\_Option\_get:} retrieve a matrix option} \end{verbatim} } \end{mdframed} This usage of \verb'GxB_get' retrieves the value of a matrix option. -The \verb'field' parameter can be \verb'GxB_HYPER' or \verb'GxB_FORMAT'. +The \verb'field' parameter can be \verb'GxB_HYPER', \verb'GxB_IS_HYPER', +or \verb'GxB_FORMAT'. For example: +\vspace{-0.1in} {\footnotesize \begin{verbatim} double h ; + bool is_hyper ; + GxB_get (A, GxB_IS_HYPER, &is_hyper) ; GxB_get (A, GxB_HYPER, &h) ; printf ("matrix A has hyper_ratio = %g\n", h) ; - + printf ("matrix A is currently %shypersparse\n", is_hyper ? "not " : " ") ; GxB_Format_Value s ; GxB_get (A, GxB_FORMAT, &s) ; - if (s == GxB_BY_COL) printf ("matrix A is stored by column\n") : - else printf ("matrix A is stored by row\n") ; \end{verbatim} } + printf ("matrix A is stored by %s\n", (s == GxB_BY_COL) ? "col" : "row") ; \end{verbatim} } %=============================================================================== \subsection{{\sf GxB\_Desc\_get:} retrieve a {\sf GrB\_Descriptor} value} @@ -6314,11 +6782,14 @@ \subsection{Summary of usage of {\sf GxB\_set} and {\sf GxB\_get}} GxB_set (GxB_FORMAT, GxB_BY_COL) ; GxB_get (GxB_FORMAT, GxB_Format_Value *s) ; - GxB_set (GxB_THREADS, int nthreads_max) ; - GxB_get (GxB_THREADS, int *nthreads_max) ; + GxB_set (GxB_NTHREADS, int nthreads_max) ; + GxB_get (GxB_NTHREADS, int *nthreads_max) ; GxB_set (GxB_CHUNK, double chunk) ; - GxB_get (GxB_CHUNK, double *chunk) ; \end{verbatim} } + GxB_get (GxB_CHUNK, double *chunk) ; + + GxB_set (GxB_BURBLE, bool burble) ; + GxB_get (GxB_BURBLE, bool *burble) ; \end{verbatim} } \noindent To get global options that can be queried but not modified: @@ -6607,7 +7078,7 @@ \section{SuiteSparse:GraphBLAS Colon and Index Notation} %%%%%%%%%%%%%%%%%%%%%%% are extensions to the specification. \end{spec} -\newpage +% \newpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{GraphBLAS Operations} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -6615,7 +7086,7 @@ \section{GraphBLAS Operations} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% The next sections define each of the GraphBLAS operations, also listed in the table below. SuiteSparse:GraphBLAS extensions (\verb'GxB_subassign', -\verb'GxB_select' and \verb'GxB_kron') are included in the table. +\verb'GxB_select') are included in the table. \vspace{0.2in} {\small @@ -6644,6 +7115,10 @@ \section{GraphBLAS Operations} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \hline \verb'GrB_apply' & apply unary operator & ${\bf C \langle M \rangle = C \odot} f{\bf (A)}$ \\ & & ${\bf w \langle m \rangle = w \odot} f{\bf (u)}$ \\ + & apply binary operator & ${\bf C \langle M \rangle = C \odot} f(x,{\bf A})$ \\ + & & ${\bf C \langle M \rangle = C \odot} f({\bf A},y)$ \\ + & & ${\bf w \langle m \rangle = w \odot} f(x,{\bf x})$ \\ + & & ${\bf w \langle m \rangle = w \odot} f({\bf u},y)$ \\ \hline \verb'GxB_select' & apply select operator & ${\bf C \langle M \rangle = C \odot} f{\bf (A,k)}$ \\ & & ${\bf w \langle m \rangle = w \odot} f{\bf (u,k)}$ \\ @@ -6653,221 +7128,12 @@ \section{GraphBLAS Operations} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \hline \verb'GrB_transpose' & transpose & ${\bf C \langle M \rangle = C \odot A^{\sf T}}$ \\ \hline -\verb'GxB_kron' & Kronecker product & ${\bf C \langle M \rangle = C \odot \mbox{kron}(A, B)}$ \\ -\hline -\end{tabular} -} -\vspace{0.2in} - - - - -\newpage -%=============================================================================== -\subsection{The GraphBLAS specification in {MATLAB}} %========================== -%=============================================================================== -\label{spec} - -SuiteSparse:GraphBLAS includes a MATLAB implementation of nearly the entire -GraphBLAS specification, including all built-in types and operators. The -typecasting rules and integer operator rules from GraphBLAS are implemented in -MATLAB via \verb'mexFunctions' that call the GraphBLAS routines in C. All -other functions are written purely in MATLAB \verb'M'-files, and are given -names of the form \verb'GB_spec_*'. All of these MATLAB interfaces and -\verb'M'-file functions they are provided in the software distribution of -SuiteSparse:GraphBLAS. The purpose of this is two-fold: - -\begin{itemize} - -\item {\bf Illustration and documentation:} MATLAB is so expressive, and so - beautiful to read and write, that the \verb'GB_spec_*' functions read - almost like the exact specifications from the GraphBLAS API. - Excerpts and condensed versions of these functions have - already been used to this point in the User Guide, such as - Figure~\ref{fig_accummask}, and the subsequent sections rely on them as - well. This is why the discussion here is not just relegated to an Appendix - on testing; the reader can benefit from studying the \verb'GB_spec_*' - functions to understand what a GraphBLAS operation is computing. For - example, \verb'GrB_mxm' (Section~\ref{mxm}) includes a condensed and - simplified version of \verb'GB_spec_mxm'. - -\item {\bf Testing:} Testing the C interface to SuiteSparse:GraphBLAS is a - significant challenge since it supports so many different kinds of - operations on a vast range of semirings. It is difficult to tell from - looking at the result from a C function in GraphBLAS if the result is - correct. Thus, each function has been written twice: once in a - highly-optimized function in C, and again in a simple and elegant MATLAB - function. The latter is almost a direct translation of all the mathematics - behind the GraphBLAS API, so it is much easier to visually - inspect the \verb'GB_spec_*' version in MATLAB to ensure the correct - mathematics are being computed. - -\end{itemize} - -The following functions are included in the SuiteSparse:GraphBLAS software -distribution. Each has a name of the form \verb'GB_spec_*', and each of them -is a ``mimic'' of a corresponding C function in GraphBLAS. Not all functions -in the C API have a corresponding mimic; in particular, many of the vector -functions can be computed directly with the corresponding matrix version in the -MATLAB implementations. A list of these files is shown below: - -\vspace{0.2in} -{\footnotesize -\begin{tabular}{lll} -MATLAB \verb'GB_spec' function & corresponding GraphBLAS & Section \\ - & function or method & \\ -\hline -\verb'GB_spec_accum.m' & ${\bf Z = C \odot T}$ & \ref{accummask} \\ -\verb'GB_spec_mask.m' & ${\bf C \langle M \rangle = Z}$ & \ref{accummask} \\ -\verb'GB_spec_accum_mask.m' & ${\bf C \langle M \rangle = C \odot T}$ & \ref{accummask} \\ -\hline -\verb'GB_spec_Vector_extractElement.m' & \verb'GrB_Vector_extractElement' & \ref{vector_extractElement} \\ -\hline -\verb'GB_spec_build.m' & \verb'GrB_Matrix_build' & \ref{matrix_build} \\ -\verb'GB_spec_Matrix_extractElement.m' & \verb'GrB_Matrix_extractElement' & \ref{matrix_extractElement} \\ -\verb'GB_spec_extractTuples.m' & \verb'GrB_Matrix_extractTuples' & \ref{matrix_extractTuples} \\ -\hline -\verb'GB_spec_mxm.m' & \verb'GrB_mxm' & \ref{mxm} \\ -\verb'GB_spec_vxm.m' & \verb'GrB_vxm' & \ref{vxm} \\ -\verb'GB_spec_mxv.m' & \verb'GrB_mxv' & \ref{mxv} \\ -\hline -\verb'GB_spec_eWiseMult_Vector.m' & \verb'GrB_eWiseMult_Vector' & \ref{eWiseMult} \\ -\verb'GB_spec_eWiseMult_Matrix.m' & \verb'GrB_eWiseMult_Matrix' & \ref{eWiseMult} \\ -\verb'GB_spec_eWiseAdd_Vector.m' & \verb'GrB_eWiseAdd_Vector' & \ref{eWiseAdd} \\ -\verb'GB_spec_eWiseAdd_Matrix.m' & \verb'GrB_eWiseAdd_Matrix' & \ref{eWiseAdd} \\ -\hline -\verb'GB_spec_Vector_extract.m' & \verb'GrB_Vector_extract' & \ref{extract_vector} \\ -\verb'GB_spec_Matrix_extract.m' & \verb'GrB_Matrix_extract' & \ref{extract_matrix} \\ -\verb'GB_spec_Col_extract.m' & \verb'GrB_Col_extract' & \ref{extract_column} \\ -\hline -\verb'GB_spec_subassign.m' & \verb'GxB_subassign' & \ref{subassign} \\ -\verb'GB_spec_assign.m' & \verb'GrB_assign' & \ref{assign} \\ -\hline -\verb'GB_spec_apply.m' & \verb'GrB_apply' & \ref{apply} \\ -\hline -\verb'GB_spec_select.m' & \verb'GxB_select' & \ref{select} \\ -\hline -\verb'GB_spec_reduce_to_vector.m' & \verb'GrB_reduce' (to vector) & \ref{reduce_to_vector} \\ -\verb'GB_spec_reduce_to_scalar.m' & \verb'GrB_reduce' (to scalar) & \ref{reduce_matrix_to_scalar} \\ -\hline -\verb'GB_spec_transpose.m' & \verb'GrB_transpose' & \ref{transpose} \\ -\hline -\verb'GB_spec_kron.m' & \verb'GxB_kron' & \ref{kron} \\ +\verb'GrB_kronecker' & Kronecker product & ${\bf C \langle M \rangle = C \odot \mbox{kron}(A, B)}$ \\ \hline \end{tabular} } \vspace{0.2in} -Additional files are included for creating test problems and providing -inputs to the above files, or supporting functions: - -\vspace{0.1in} -{\footnotesize -\begin{tabular}{ll} -MATLAB \verb'GB_spec' function & purpose \\ -\hline -\verb'GB_spec_compare.m' & Compares output of C and MATLAB functions \\ -\verb'GB_spec_random.m' & Generates a random matrix \\ -\verb'GB_spec_op.m' & MATLAB mimic of built-in operators \\ -\verb'GB_spec_operator.m' & Like \verb'GrB_*Op_new' \\ -\verb'GB_spec_opsall.m' & List operators, types, and semirings \\ -\verb'GB_spec_semiring.m' & Like \verb'GrB_Semiring_new' \\ -\verb'GB_spec_descriptor.m' & mimics a GraphBLAS descriptor \\ -\verb'GB_spec_identity.m' & returns the identity of a monoid \\ -\verb'GB_spec_matrix.m' & conforms a MATLAB sparse matrix to GraphBLAS \\ -\verb'GB_define.m' & creates draft of \verb'GraphBLAS.h' \\ -\hline -\end{tabular} -} - -\newpage -An intensive test suite has been written that generates test graphs in MATLAB, -then computes the result in both the C version of the SuiteSparse:GraphBLAS and -in the MATLAB \verb'GB_spec_*' functions. Each C function in GraphBLAS has -a direct \verb'mexFunction' interface that allow the test suite in MATLAB -to call both functions. - -This approach has its limitations: - -\begin{itemize} -\item {\bf matrix classes:} MATLAB only supports sparse double, sparse double - complex, and sparse logical matrices. MATLAB can represent dense matrices - in all eleven built-in GraphBLAS data types, so in all these specification - \verb'M'-files, the matrices are either in dense format in the - corresponding MATLAB class, or they are held as sparse double or sparse - logical, and the actual GraphBLAS type is held with it as a string member - of a MATLAB \verb'struct'. To ensure the correct typecasting is computed, - most of the MATLAB scripts work on dense matrices, not sparse ones. As a - result, the MATLAB \verb'GB_spec_*' function are not meant for production - use, but just for testing and illustration. - -\item {\bf integer operations:} MATLAB and GraphBLAS handle integer operations - differently. In MATLAB, an integer result outside the range of the integer - is set to maximum or minimum integer. For example, \verb'int8(127)+1' is - \verb'127'. This is useful for many computations such as image processing, - but GraphBLAS follows the C rules instead, where integer values wrap, - modulo style. For example, in GraphBLAS and in C, incrementing - \verb'(int8_t) 127' by one results in \verb'-128'. Of course, an - alternative would be for a MATLAB interface to create its own integer - operators, each of which would follow the MATLAB integer rules of - arithmetic. However, this would obscure the purpose of these - \verb'GB_spec_*' and \verb'GB_mex_*' test functions, which is to test the C - API of GraphBLAS. When the \verb'GB_spec_*' functions need to perform - integer computations and typecasting, they call GraphBLAS to do the work, - instead doing the work in MATLAB. This ensures that the \verb'GB_spec_*' - functions obtain the same results as their GraphBLAS counterparts. - -\item {\bf elegance:} to simplify testing, each MATLAB \verb'mexFunction' - interface a GraphBLAS function is a direct translation of the C API. For - example, \verb'GB_mex_mxm' is a direct interface to the GraphBLAS - \verb'GrB_mxm', even down the order of parameters. This approach - abandons some of the potential features of MATLAB for creating elegant - \verb'M'-file interfaces in a highly usable form, such as the ability to - provide fewer parameters when optional parameters are not in use. These - \verb'mexFunctions', as written, are not meant to be usable in a user - application. They are not highly documented. They are meant to be fast, - and direct, to accomplish the goal of testing SuiteSparse:GraphBLAS in - MATLAB and comparing their results with the corresponding \verb'GB_spec_*' - function. They are not recommended for use in general applications in - MATLAB. - -\item {\bf generality:} the MATLAB \verb'mexFunction' interface needs to - test the C API directly, so it must access content of SuiteSparse:GraphBLAS - objects that are normally opaque to an end user application. As a result, - these \verb'mexFunctions' do not serve as a general interface to any - conforming GraphBLAS implementation, but only to SuiteSparse:GraphBLAS. - -\end{itemize} - -In the MATLAB mimic functions, \verb'GB_spec_*', a GraphBLAS matrix \verb'A' is -represented as a MATLAB \verb'struct' with the following components: - -\begin{itemize} -\item \verb'A.matrix': the values of the matrix. If \verb'A.matrix' is a - sparse double matrix, it holds a typecasted copy of the values of a - GraphBLAS matrix, unless the GraphBLAS matrix is also double - (\verb'GrB_FP64'). - -\item \verb'A.pattern': a logical matrix holding the pattern; - \verb'A.pattern(i,j)=true' if \verb'(i,j)' is in the pattern of \verb'A', - and \verb'false' otherwise. - -\item \verb'A.class': the MATLAB class of the matrix corresponding to one of - the eleven built-in types. Normally this is simply \verb'class(A.matrix)'. - -\item \verb'A.values': most of the GraphBLAS test \verb'mexFunctions' return - their result as a MATLAB sparse matrix, in the \verb'double' class. This - works well for all types except for the 64-bit integer types, since a - double has about 54 bits of mantissa which is less than the 64 bits - available in a long integer. To ensure no bits are lots, these values are - also returned as a vector. This enables \verb'GB_spec_compare' to ensure - the test results are identical down to the very last bit, and not just to - within roundoff error. Nearly all tests, even in double precision, check - for perfect equality, not just for results accurate to within round-off - error. - -\end{itemize} - \newpage %=============================================================================== \subsection{{\sf GrB\_mxm:} matrix-matrix multiply} %=========================== @@ -6894,8 +7160,9 @@ \subsection{{\sf GrB\_mxm:} matrix-matrix multiply} %=========================== according to the descriptor, \verb'desc' (which may be \verb'NULL') and then typecasted to match the multiply operator of the \verb'semiring'. Next, \verb'T=A*B' is computed on the \verb'semiring', precisely defined in the -\verb'GB_spec_mxm.m' script. The actual algorithm exploits sparsity and does -not take $O(n^3)$ time, but what computes is the following: +\verb'GB_spec_mxm.m' script in \verb'GraphBLAS/Test'. The actual algorithm +exploits sparsity and does not take $O(n^3)$ time, but it computes the +following: {\footnotesize \begin{verbatim} @@ -7109,7 +7376,7 @@ \subsubsection{{\sf GrB\_eWiseMult\_Vector:} element-wise vector multiply} \end{verbatim} } \end{mdframed} -\verb'GrB_eWiseMult_Vector' computes the element-wise ``multiplication'' of two +\verb'GrB_Vector_eWiseMult' computes the element-wise ``multiplication'' of two vectors \verb'u' and \verb'v', element-wise using any binary operator (not just times). The vectors are not transposed via the descriptor. The vectors \verb'u' and \verb'v' are first typecasted into the first and second inputs of @@ -7153,7 +7420,7 @@ \subsubsection{{\sf GrB\_eWiseMult\_Matrix:} element-wise matrix multiply} \end{verbatim} } \end{mdframed} -\verb'GrB_eWiseMult_Matrix' computes the element-wise ``multiplication'' of two +\verb'GrB_Matrix_eWiseMult' computes the element-wise ``multiplication'' of two matrices \verb'A' and \verb'B', element-wise using any binary operator (not just times). The input matrices may be transposed first, according to the descriptor \verb'desc'. They are then typecasted into the first and second @@ -7276,7 +7543,7 @@ \subsubsection{{\sf GrB\_eWiseAdd\_Vector:} element-wise vector addition} ) ; \end{verbatim} } \end{mdframed} -\verb'GrB_eWiseAdd_Vector' computes the element-wise ``addition'' of two +\verb'GrB_Vector_eWiseAdd' computes the element-wise ``addition'' of two vectors \verb'u' and \verb'v', element-wise using any binary operator (not just plus). The vectors are not transposed via the descriptor. Entries in the intersection of \verb'u' and \verb'v' are first typecasted into the first and @@ -7316,7 +7583,7 @@ \subsubsection{{\sf GrB\_eWiseAdd\_Matrix:} element-wise matrix addition} ) ; \end{verbatim} } \end{mdframed} -\verb'GrB_eWiseAdd_Matrix' computes the element-wise ``addition'' of two +\verb'GrB_Matrix_eWiseAdd' computes the element-wise ``addition'' of two matrices \verb'A' and \verb'B', element-wise using any binary operator (not just plus). The input matrices may be transposed first, according to the descriptor \verb'desc'. Entries in the intersection then typecasted into the @@ -8181,11 +8448,11 @@ \subsection{Duplicate indices in {\sf GrB\_assign} and {\sf GxB\_subassign}} GrB_Index I [2] = {0, 0} ; GrB_Vector_setElement (y, 5, 0) ; GrB_Vector_setElement (y, 7, 1) ; - GrB_wait ( ) ; + GrB_Vector_wait (&y) ; GxB_print (x, 3) ; GxB_print (y, 3) ; GrB_assign (x, NULL, GrB_MIN_INT32, y, I, 2, NULL) ; - GrB_wait ( ) ; + GrB_Vector_wait (&y) ; GxB_print (x, 3) ; GrB_finalize ( ) ; } @@ -8376,21 +8643,22 @@ \subsection{Comparing {\sf GrB\_assign} and {\sf GxB\_subassign}} %============= is in the ${\bf C(I,J)}$ submatrix, and it describes what is computed for both \verb'GrB_assign' and \verb'GxB_subassign'. They perform the exact same computation; the only difference is how the value of the mask is -specified. +specified. Compare Table~\ref{insubmatrix} with Table~\ref{tab:maskaccum} +in Section~\ref{sec:maskaccum}. -The first column of the table is {\em yes} if \verb'GrB_REPLACE' is enabled, +The first column of Table~\ref{insubmatrix} is {\em yes} if \verb'GrB_REPLACE' is enabled, and a dash otherwise. The second column is {\em yes} if an accumulator operator is given, and a dash otherwise. The third column is $c_{ij}$ if the entry is present in ${\bf C}$, and a dash otherwise. The fourth column is $a_{i'j'}$ if the corresponding entry is present in ${\bf A}$, where $i={\bf I}(i')$ and $j={\bf J}(i')$. -The {\em mask} column is 1 if the mask allows ${\bf C}$ to be modified, and 0 -otherwise. This is $m_{ij}$ for \verb'GrB_assign', and $m_{i'j'}$ for -\verb'GxB_subassign', to reflect the difference in the mask, but this -difference is not reflected in the table. The value 1 or 0 is the value of the -entry in the mask after it is optionally complemented via the \verb'GrB_COMP' -option. +The {\em mask} column is 1 if the effective value of the mask mask allows ${\bf +C}$ to be modified, and 0 otherwise. This is $m_{ij}$ for \verb'GrB_assign', +and $m_{i'j'}$ for \verb'GxB_subassign', to reflect the difference in the mask, +but this difference is not reflected in the table. The value 1 or 0 is the +value of the entry in the mask after it is optionally complemented via the +\verb'GrB_COMP' option. Finally, the last column is the action taken in this case. It is left blank if no action is taken, in which case $c_{ij}$ is not modified if present, or not @@ -8406,36 +8674,37 @@ \subsection{Comparing {\sf GrB\_assign} and {\sf GxB\_subassign}} %============= - &- & - & $a_{i'j'}$ & 1 & $c_{ij} = a_{i'j'}$, insert \\ - &- & $c_{ij}$ & - & 1 & delete $c_{ij}$ because $a_{i'j'}$ not present \\ - &- & - & - & 1 & \\ -\hline - - &- & $c_{ij}$ & $a_{i'j'}$ & 0 & \\ - - &- & - & $a_{i'j'}$ & 0 & \\ - - &- & $c_{ij}$ & - & 0 & \\ - - &- & - & - & 0 & \\ \hline yes&- & $c_{ij}$ & $a_{i'j'}$ & 1 & $c_{ij} = a_{i'j'}$, update \\ yes&- & - & $a_{i'j'}$ & 1 & $c_{ij} = a_{i'j'}$, insert \\ yes&- & $c_{ij}$ & - & 1 & delete $c_{ij}$ because $a_{i'j'}$ not present \\ yes&- & - & - & 1 & \\ -\hline - yes&- & $c_{ij}$ & $a_{i'j'}$ & 0 & delete $c_{ij}$ (because of \verb'GrB_REPLACE') \\ - yes&- & - & $a_{i'j'}$ & 0 & \\ - yes&- & $c_{ij}$ & - & 0 & delete $c_{ij}$ (because of \verb'GrB_REPLACE') \\ - yes&- & - & - & 0 & \\ \hline - &yes & $c_{ij}$ & $a_{i'j'}$ & 1 & $c_{ij} = c_{ij} \odot a_{i'j'}$, apply accumulator \\ - &yes & - & $a_{i'j'}$ & 1 & $c_{ij} = a_{i'j'}$, insert \\ - &yes & $c_{ij}$ & - & 1 & \\ - &yes & - & - & 1 & \\ -\hline - - &yes & $c_{ij}$ & $a_{i'j'}$ & 0 & \\ - - &yes & - & $a_{i'j'}$ & 0 & \\ - - &yes & $c_{ij}$ & - & 0 & \\ - - &yes & - & - & 0 & \\ \hline yes&yes & $c_{ij}$ & $a_{i'j'}$ & 1 & $c_{ij} = c_{ij} \odot a_{i'j'}$, apply accumulator \\ yes&yes & - & $a_{i'j'}$ & 1 & $c_{ij} = a_{i'j'}$, insert \\ yes&yes & $c_{ij}$ & - & 1 & \\ yes&yes & - & - & 1 & \\ +\hline +\hline + - &- & $c_{ij}$ & $a_{i'j'}$ & 0 & \\ + - &- & - & $a_{i'j'}$ & 0 & \\ + - &- & $c_{ij}$ & - & 0 & \\ + - &- & - & - & 0 & \\ +\hline + yes&- & $c_{ij}$ & $a_{i'j'}$ & 0 & delete $c_{ij}$ (because of \verb'GrB_REPLACE') \\ + yes&- & - & $a_{i'j'}$ & 0 & \\ + yes&- & $c_{ij}$ & - & 0 & delete $c_{ij}$ (because of \verb'GrB_REPLACE') \\ + yes&- & - & - & 0 & \\ +\hline + - &yes & $c_{ij}$ & $a_{i'j'}$ & 0 & \\ + - &yes & - & $a_{i'j'}$ & 0 & \\ + - &yes & $c_{ij}$ & - & 0 & \\ + - &yes & - & - & 0 & \\ \hline yes&yes & $c_{ij}$ & $a_{i'j'}$ & 0 & delete $c_{ij}$ (because of \verb'GrB_REPLACE') \\ yes&yes & - & $a_{i'j'}$ & 0 & \\ @@ -8480,24 +8749,25 @@ \subsection{Comparing {\sf GrB\_assign} and {\sf GxB\_subassign}} %============= \hline - &- & $c_{ij}$ & $c_{ij}$ & 1 & \\ - &- & - & - & 1 & \\ -\hline - - &- & $c_{ij}$ & $c_{ij}$ & 0 & \\ - - &- & - & - & 0 & \\ \hline yes & - & $c_{ij}$ & $c_{ij}$ & 1 & \\ yes & - & - & - & 1 & \\ -\hline - yes & - & $c_{ij}$ & $c_{ij}$ & 0 & delete $c_{ij}$ (because of \verb'GrB_REPLACE') \\ - yes & - & - & - & 0 & \\ \hline - &yes & $c_{ij}$ & $c_{ij}$ & 1 & \\ - &yes & - & - & 1 & \\ -\hline - - &yes & $c_{ij}$ & $c_{ij}$ & 0 & \\ - - &yes & - & - & 0 & \\ \hline yes & yes & $c_{ij}$ & $c_{ij}$ & 1 & \\ yes & yes & - & - & 1 & \\ +\hline +\hline + - &- & $c_{ij}$ & $c_{ij}$ & 0 & \\ + - &- & - & - & 0 & \\ +\hline + yes & - & $c_{ij}$ & $c_{ij}$ & 0 & delete $c_{ij}$ (because of \verb'GrB_REPLACE') \\ + yes & - & - & - & 0 & \\ +\hline + - &yes & $c_{ij}$ & $c_{ij}$ & 0 & \\ + - &yes & - & - & 0 & \\ \hline yes & yes & $c_{ij}$ & $c_{ij}$ & 0 & delete $c_{ij}$ (because of \verb'GrB_REPLACE') \\ yes & yes & - & - & 0 & \\ @@ -8689,7 +8959,8 @@ \subsubsection{Performance of {\sf GxB\_subassign}, {\sf GrB\_assign} Section~\ref{compare_assign}. It can be up to 500x faster than MATLAB R2019b, or even higher depending on the kind of matrix assignment. MATLAB logical indexing (the mask of GraphBLAS) is much faster with -GraphBLAS than in MATLAB R2019b. +GraphBLAS than in MATLAB R2019b; differences of up to 100,000x have been +observed. All of the 28 variants (each with their own source code) are either asymptotically optimal, or to within a log factor of being asymptotically @@ -8702,14 +8973,18 @@ \subsubsection{Performance of {\sf GxB\_subassign}, {\sf GrB\_assign} \newpage %=============================================================================== -\subsection{{\sf GrB\_apply:} apply a unary operator} %========================= +\subsection{{\sf GrB\_apply:} apply a unary or binary operator} %=============== %=============================================================================== \label{apply} -The \verb'GrB_apply' function is the generic name for two specific functions: -\\ \verb'GrB_Vector_apply' and \verb'GrB_Matrix_apply'. The generic name -appears in the function prototypes, but the specific function name is used when -describing each variation. When discussing features that apply to both +\verb'GrB_apply' is the generic name for 62 specific functions. +\verb'GrB_Vector_apply' and \verb'GrB_Matrix_apply' apply a unary operator to +the entries of a matrix. \verb'GrB_*_apply_BinaryOp1st*' applies a binary +operator where a single scalar is provided as the $x$ input to the binary +operator. \verb'GrB_*_apply_BinaryOp2nd*' applies a binary operator where a +single scalar is provided as the $y$ input to the binary operator. The generic +name appears in the function prototypes, but the specific function name is used +when describing each variation. When discussing features that apply to all versions, the simple name \verb'GrB_apply' is used. % \newpage @@ -8775,6 +9050,10 @@ \subsubsection{{\sf GrB\_Matrix\_apply:} apply a unary operator to a matrix} are very useful when combined with this function, enabling it to compute ${\bf C \langle M \rangle = C \odot A}$. This makes \verb'GrB_apply' a direct interface to the accumulator/mask function for both matrices and vectors. +The \verb'GrB_IDENTITY_'$T$ operators also provide the fastest stand-alone +typecasting methods in SuiteSparse:GraphBLAS, with all $13 \times 13=169$ +methods appearing as individual functions, to typecast between any of the 13 +built-in types. To compute ${\bf C \langle M \rangle = A}$ or ${\bf C \langle M \rangle = C \odot A}$ for user-defined types, the user application would need to define an @@ -8789,6 +9068,110 @@ \subsubsection{{\sf GrB\_Matrix\_apply:} apply a unary operator to a matrix} both built-in and user-defined types. However, it is only available for matrices, not vectors. +\newpage +%=============================================================================== +\subsubsection{{\sf GrB\_Vector\_apply\_BinaryOp1st:} apply a binary operator to a vector; 1st scalar binding} +%=============================================================================== +\label{vector_apply1st} + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_apply // w = accum (w, op(x,u)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + x, // first input: scalar x + const GrB_Vector u, // second input: vector u + const GrB_Descriptor desc // descriptor for w and mask +) ; +\end{verbatim} } \end{mdframed} + +\verb'GrB_Vector_apply_BinaryOp1st_' applies a binary operator +$z=f(x,y)$ to a vector, where a scalar $x$ is bound to the first input of the +operator. It is otherwise identical to \verb'GrB_Vector_apply'. With no +suffix, \verb'GxB_Vector_apply_BinaryOp1st' takes as input a \verb'GxB_Scalar'. + +%=============================================================================== +\subsubsection{{\sf GrB\_Vector\_apply\_BinaryOp2nd:} apply a binary operator to a vector; 2nd scalar binding} +%=============================================================================== +\label{vector_apply2nd} + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_apply // w = accum (w, op(u,y)) +( + GrB_Vector w, // input/output vector for results + const GrB_Vector mask, // optional mask for w, unused if NULL + const GrB_BinaryOp accum, // optional accum for z=accum(w,t) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Vector u, // first input: vector u + y, // second input: scalar y + const GrB_Descriptor desc // descriptor for w and mask +) ; +\end{verbatim} } \end{mdframed} + +\verb'GrB_Vector_apply_BinaryOp2nd_' applies a binary operator +$z=f(x,y)$ to a vector, where a scalar $y$ is bound to the second input of the +operator. It is otherwise identical to \verb'GrB_Vector_apply'. With no +suffix, \verb'GxB_Vector_apply_BinaryOp2nd' takes as input a \verb'GxB_Scalar'. + +\newpage +%=============================================================================== +\subsubsection{{\sf GrB\_Matrix\_apply\_BinaryOp1st:} apply a binary operator to a matrix; 1st scalar binding} +%=============================================================================== +\label{matrix_apply1st} + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_apply // C=accum(C,op(x,A)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + x, // first input: scalar x + const GrB_Matrix A, // second input: matrix A + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; +\end{verbatim} } \end{mdframed} + +\verb'GrB_Matrix_apply_BinaryOp1st_' applies a binary operator +$z=f(x,y)$ to a matrix, where a scalar $x$ is bound to the first input of the +operator. It is otherwise identical to \verb'GrB_Matrix_apply'. With no +suffix, \verb'GxB_Matrix_apply_BinaryOp1st' takes as input a \verb'GxB_Scalar'. +To transpose the input matrix, use the \verb'GrB_INP0' descriptor setting. + +%=============================================================================== +\subsubsection{{\sf GrB\_Matrix\_apply\_BinaryOp2nd:} apply a binary operator to a matrix; 2nd scalar binding} +%=============================================================================== +\label{matrix_apply2nd} + +\begin{mdframed}[userdefinedwidth=6in] +{\footnotesize +\begin{verbatim} +GrB_Info GrB_apply // C=accum(C,op(A,y)) +( + GrB_Matrix C, // input/output matrix for results + const GrB_Matrix Mask, // optional mask for C, unused if NULL + const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) + const GrB_BinaryOp op, // operator to apply to the entries + const GrB_Matrix A, // first input: matrix A + y, // second input: scalar y + const GrB_Descriptor desc // descriptor for C, mask, and A +) ; +\end{verbatim} } \end{mdframed} + +\verb'GrB_Matrix_apply_BinaryOp2nd_' applies a binary operator +$z=f(x,y)$ to a matrix, where a scalar $x$ is bound to the second input of the +operator. It is otherwise identical to \verb'GrB_Matrix_apply'. With no +suffix, \verb'GxB_Matrix_apply_BinaryOp2nd' takes as input a \verb'GxB_Scalar'. +To transpose the input matrix, use the \verb'GrB_INP1' descriptor setting. + \newpage %=============================================================================== \subsection{{\sf GxB\_select:} apply a select operator} %======================= @@ -9098,10 +9481,6 @@ \subsubsection{{\sf GrB\_Vector\_reduce\_$<$type$>$:} reduce a vector to a scala the \verb'ztype' of the \verb'accum' operator. Finally, \verb'z' is typecast into the final result, \verb'c'. -\paragraph{Forced completion:} -All computations for the vector \verb'u' are -guaranteed to be finished when the method returns. - \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Matrix\_reduce\_$<$type$>$:} reduce a matrix to a scalar} @@ -9127,10 +9506,6 @@ \subsubsection{{\sf GrB\_Matrix\_reduce\_$<$type$>$:} reduce a matrix to a scala or vector have no effect on the result. Refer to the reduction to scalar described in the previous Section~\ref{reduce_vector_to_scalar}. -\paragraph{Forced completion:} -All computations for the matrix \verb'A' are -guaranteed to be finished when the method returns. - \newpage %=============================================================================== \subsection{{\sf GrB\_transpose:} transpose a matrix} %========================= @@ -9239,26 +9614,26 @@ \subsection{{\sf GrB\_transpose:} transpose a matrix} %========================= \newpage %=============================================================================== -\subsection{{\sf GxB\_kron:} Kronecker product} %=============================== +\subsection{{\sf GrB\_kronecker:} Kronecker product} %========================== %=============================================================================== \label{kron} \begin{mdframed}[userdefinedwidth=6in] {\footnotesize \begin{verbatim} -GrB_Info GxB_kron // C = accum (C, kron(A,B)) +GrB_Info GrB_kronecker // C = accum (C, kron(A,B)) ( GrB_Matrix C, // input/output matrix for results const GrB_Matrix Mask, // optional mask for C, unused if NULL const GrB_BinaryOp accum, // optional accum for Z=accum(C,T) - const GrB_BinaryOp op, // defines '*' for T=kron(A,B) + const op, // defines '*' for T=kron(A,B) const GrB_Matrix A, // first input: matrix A const GrB_Matrix B, // second input: matrix B const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; \end{verbatim} } \end{mdframed} -\verb'GxB_kron' computes the Kronecker product, +\verb'GrB_kronecker' computes the Kronecker product, ${\bf C \langle M \rangle = C \odot \mbox{kron}(A,B)}$ where \[ \mbox{kron}{\bf (A,B)} = @@ -9281,9 +9656,9 @@ \subsection{{\sf GxB\_kron:} Kronecker product} %=============================== operator, \verb'op'. The final step is ${\bf C \langle M \rangle = C \odot T}$, as described in Section~\ref{accummask}. -\begin{spec} -{\bf SPEC:} \verb'GxB_kron' is an extension to the spec. -\end{spec} +The operator \verb'op' may be a \verb'GrB_BinaryOp', a \verb'GrB_Monoid', or a +\verb'GrB_Semiring'. In the latter case, the multiplicative operator of +the semiring is used. \newpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -9335,14 +9710,13 @@ \section{Printing GraphBLAS objects} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% complete any computations prior to printing or checking the contents of the matrix or vector, then further errors could occur, including a segfault. -By contrast, all GraphBLAS methods and operations that return values into -user-provided arrays or variables force the completion of pending operations -(\verb'GrB_*_nvals', \verb'GrB_*_extractElement', \verb'GrB_*_extractTuples', -and \verb'GrB_reduce' (to scalar)). The \verb'GxB_*print' methods provide -a useful alternative for debugging, and for a quick understanding of what -GraphBLAS is computing while developing a user application. +By contrast, GraphBLAS methods and operations that return values into +user-provided arrays or variables might finish pending operations before the +return these values, and this would change their state. Since they do not +change the state of any object, the \verb'GxB_*print' methods provide a useful +alternative for debugging, and for a quick understanding of what GraphBLAS is +computing while developing a user application. -\newpage Each of the methods has a parameter of type \verb'GxB_Print_Level' that specifies the amount to print: @@ -9353,7 +9727,9 @@ \section{Printing GraphBLAS objects} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% GxB_SILENT = 0, // nothing is printed, just check the object GxB_SUMMARY = 1, // print a terse summary GxB_SHORT = 2, // short description, about 30 entries of a matrix - GxB_COMPLETE = 3 // print the entire contents of the object + GxB_COMPLETE = 3, // print the entire contents of the object + GxB_SHORT_VERBOSE = 4, // GxB_SHORT but with "%.15g" for doubles + GxB_COMPLETE_VERBOSE = 5 // GxB_COMPLETE but with "%.15g" for doubles } GxB_Print_Level ; \end{verbatim}} @@ -9365,10 +9741,8 @@ \section{Printing GraphBLAS objects} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% name of the object itself. If the file \verb'f' is \verb'NULL', nothing is printed (\verb'pr' is -effectively \verb'GxB_SILENT') If \verb'pr' is outside the bounds 0 to 3, -negative values are treated as \verb'GxB_SILENT', and values larger than 3 are -treated as \verb'GxB_COMPLETE'. If \verb'name' is \verb'NULL', it is treated -as the empty string. None of these are error conditions. +effectively \verb'GxB_SILENT'). If \verb'name' is \verb'NULL', it is treated +as the empty string. These are not error conditions. The methods check their input objects carefully and extensively, even when \verb'pr' is equal to \verb'GxB_SILENT'. The following error codes can be @@ -9390,7 +9764,7 @@ \section{Printing GraphBLAS objects} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% by trying to parse the resulting output via another program. The intent of these functions is to produce a report of an object for visual inspection. If the user application needs to extract content from a GraphBLAS matrix or -vector, use \verb'GrB_*_extractTuples' instead. +vector, use \verb'GrB_*_extractTuples' or the import/export methods instead. \newpage %=============================================================================== @@ -9597,8 +9971,7 @@ \subsection{{\sf GxB\_Matrix\_fprint:} Print a {\sf GrB\_Matrix}} ) ; \end{verbatim} } \end{mdframed} -For example, -\verb'GxB_Matrix_fprint (A, "my matrix", GxB_SHORT, f)' +For example, \verb'GxB_Matrix_fprint (A, "my matrix", GxB_SHORT, f)' prints about 30 entries from the matrix \verb'A' to the file \verb'f'. @@ -9618,8 +9991,7 @@ \subsection{{\sf GxB\_Vector\_fprint:} Print a {\sf GrB\_Vector}} ) ; \end{verbatim} } \end{mdframed} -For example, -\verb'GxB_Vector_fprint (v, "my vector", GxB_SHORT, f)' +For example, \verb'GxB_Vector_fprint (v, "my vector", GxB_SHORT, f)' prints about 30 entries from the vector \verb'v' to the file \verb'f'. %=============================================================================== @@ -9638,8 +10010,7 @@ \subsection{{\sf GxB\_Scalar\_fprint:} Print a {\sf GxB\_Scalar}} ) ; \end{verbatim} } \end{mdframed} -For example, -\verb'GxB_Scalar_fprint (s, "my scalar", GxB_SHORT, f)' +For example, \verb'GxB_Scalar_fprint (s, "my scalar", GxB_SHORT, f)' prints a short description of the sparse scalar \verb's' to the file \verb'f'. \newpage @@ -9661,27 +10032,15 @@ \subsection{Performance and portability considerations} Some implementations may wish to print nothing at all if the matrix is not yet completed, or just an indication that the matrix has pending operations and cannot be printed, when non-blocking mode is employed. In this case, use -\verb'GrB_Matrix_nvals' or \verb'GrB_wait' to finish all pending computations -first. If a matrix or vector has pending operations, SuiteSparse:GraphBLAS -prints a list of the {\em pending tuples}, which are the entries not yet -inserted into the primary data structure. It can also print out entries that -remain in the data structure but are awaiting deletion; these are called {\em -zombies} in the output report. +\verb'GrB_Matrix_wait', \verb'GrB_Vector_wait', or \verb'GxB_Scalar_wait' to +finish all pending computations first. If a matrix or vector has pending +operations, SuiteSparse:GraphBLAS prints a list of the {\em pending tuples}, +which are the entries not yet inserted into the primary data structure. It can +also print out entries that remain in the data structure but are awaiting +deletion; these are called {\em zombies} in the output report. Most of the rest of the report is self-explanatory. -% \newpage -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Creating user-defined objects at compile-time (feature removed)} %%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\label{precompile} - -This feature has been removed as of SuiteSparse:GraphBLAS v3.2.0. User -objects defined with \verb'GxB_*_define' when GraphBLAS is compiled are not -compatible with the faster matrix operations. Use the run-time definitions -instead, from the GraphBLAS C API Specification (\verb'GrB_Type_new' instead of -\verb'GxB_Type_define' in the \verb'GraphBLAS/User/*.m4' script). - \newpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Examples} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -10560,7 +10919,7 @@ \subsection{Triangle counting} \newpage %------------------------------------------------------------------------------- -\subsection{User-defined types and operators: double complex and struct-based} +\subsection{User-defined types and operators} %------------------------------------------------------------------------------- \label{user} @@ -10570,16 +10929,12 @@ \subsection{User-defined types and operators: double complex and struct-based} containing a string and a 4-by-4 \verb'float' matrix. {\bf Double Complex:} -GraphBLAS does not have a native complex type, but this can be easily added +Prior to v3.3, GraphBLAS did not have a native complex type. It now appears as +the \verb'GxB_FC64' predefined type, but a complex type can also easily added as a user-defined type. The \verb'Complex_init' function in the -\verb'usercomplex.c' file in the \verb'Demo' folder creates the -\verb'Complex' type based on the ANSI C11 \verb'double complex' type. - - {\footnotesize - \begin{verbatim} - GrB_Type_new (&Complex, sizeof (double complex)) ; \end{verbatim}} - -Next, it creates a full suite of operators that correspond to every +\verb'usercomplex.c' file in the \verb'Demo' folder creates the \verb'Complex' +type based on the ANSI C11 \verb'double complex' type. +It creates a full suite of operators that correspond to every built-in GraphBLAS operator, both binary and unary. In addition, it creates the operators listed in the following table, where $D$ is \verb'double' and $C$ is \verb'Complex'. @@ -10611,7 +10966,6 @@ \subsection{User-defined types and operators: double complex and struct-based} other user application. When the user application is done, the \verb'Complex_finalize' function frees the \verb'Complex' type and its operators, monoids, and semiring. - NOTE: the \verb'Complex' type is not supported in this Demo in Microsoft Visual Studio. @@ -10633,10 +10987,12 @@ \subsection{User applications using OpenMP or POSIX pthreads} Two example demo programs are included that illustrate how a multi-threaded user application can use GraphBLAS: \verb'openmp_demo' uses OpenMP for its -user threads and \verb'pthread_demo' uses POSIX pthreads. {\bf To be -thread-safe, SuiteSparse:GraphBLAS must be compiled with a threading library, -either OpenMP or POSIX}. Either option used inside GraphBLAS can typically be -combined with any user threading model. See Section~\ref{sec:install}. +user threads and \verb'pthread_demo' uses POSIX pthreads. +% TODO in 4.0: delete this note in bold: +{\bf To be thread-safe, SuiteSparse:GraphBLAS must be compiled with a threading +library, either OpenMP or POSIX}. Either option used inside GraphBLAS can +typically be combined with any user threading model. See +Section~\ref{sec:install}. The \verb'openmp_demo' can be compiled without OpenMP, in which case it becomes single-threaded. GraphBLAS can be compiled with OpenMP, POSIX @@ -10676,6 +11032,7 @@ \subsection{User applications using OpenMP or POSIX pthreads} threads finish, the master thread prints out each matrix generated by each thread, and these results are identical for all 7 cases listed above as OK. +% TODO in 4.0: remove this; GraphBLAS will always be thread-safe: The GraphBLAS C API requires GraphBLAS to be thread-safe. If SuiteSparse:GraphBLAS is not compiled with a threading library it will not be thread-safe (the two {\em fail} cases above). For these cases, a thread will @@ -10710,10 +11067,10 @@ \subsection{On Linux and Mac} instead. {\bf NOTE: icc is generally an excellent compiler, but it will generate slower -code than gcc for v3.2.0. This is merely because of how the two compilers -treat \verb'#pragma omp atomic read' and \verb'#pragma omp atomic write'. The -use of gcc for SuiteSparse:GraphBLAS v3.2.0 is recommended. This difference in -performance should be resolved in a future version.} +code than gcc for v3.2.0 and later. This is merely because of how the two +compilers treat \verb'#pragma omp atomic read' and \verb'#pragma omp atomic write'. +The use of gcc for SuiteSparse:GraphBLAS v3.2.0 and later is recommended. This +difference in performance should be resolved in a future version.} To compile SuiteSparse:GraphBLAS and the demo programs, simply type \verb'make' in the main GraphBLAS folder, which compiles the library. To use a @@ -10796,12 +11153,14 @@ \subsection{On Microsoft Windows} See \url{https://visualstudio.microsoft.com/} for details. Version 2019 is preferred, but earlier versions may also work. -\item Open a terminal window and type the following in the - \verb'SuiteSparse/GraphBLAS/build' folder. +\item Open a terminal window and type this in the + \verb'SuiteSparse/GraphBLAS/build' folder: + \vspace{-0.1in} {\small \begin{verbatim} cmake .. \end{verbatim} } + \vspace{-0.1in} \item The \verb'cmake' command generates many files in \verb'SuiteSparse/GraphBLAS/build', and the file \verb'graphblas.sln' in @@ -10892,21 +11251,42 @@ \subsection{Compiling the MATLAB interface} or \verb'*.exp' files in the \verb'build/Release' folder. This can happen if your Windows System path is not set properly, or if Windows is not recognizing the \verb'GraphBLAS/build/Release' folder (see - Section~\ref{sec:windows}) Or, you might p have permission to change your + Section~\ref{sec:windows}) Or, you might have permission to change your Windows System path. In this case, do the following in the MATLAB Command + \vspace{-0.1in} Window: + \vspace{-0.1in} {\small \begin{verbatim} cd GraphBLAS/build/Release GrB(1) \end{verbatim} } + \vspace{-0.1in} After this step, the GraphBLAS library will be loaded into MATLAB. You may need to add the above lines in your \verb'Documents/MATLAB/startup.m' file, so that they are done each time MATLAB starts. You will also need to do this after \verb'clear all' or \verb'clear mex', since those MATLAB commands remove all loaded libraries from MATLAB. + You might also get an error ``the specified procedure cannot be found.'' + This can occur if you have upgraded your GraphBLAS library from a prior + version, and some of the compiled files \verb'@GrB/private/*.mex*' + are stale. Try the command \verb'gbmake all' in the MATLAB Command + Window, which forces all of the MATLAB interface to be recompiled. + Or, try deleting all \verb'@GrB/private/*.mex*' files and running + \verb'gbmake' again. + +\item On Windows, the \verb'casin', \verb'casinf', \verb'casinh', and + \verb'casinhf' functions provided by Microsoft do not return the correct + imaginary part. As a result, \verb'GxB_ASIN_FC32', \verb'GxB_ASIN_FC64' + \verb'GxB_ASINH_FC32', and \verb'GxB_ASINH_FC64' do not work properly on + Windows. This affects the \verb'GrB/asin', \verb'GrB/acsc', + \verb'GrB/asinh', and \verb'GrB/acsch', functions in the MATLAB interface. + See the MATLAB tests bypassed in \verb'gbtest76.m' for details, in the + \verb'GraphBLAS/GraphBLAS/test' folder. + %% FUTURE: fix asin and acsc on Windows for the complex case. + \end{enumerate} %---------------------------------------- @@ -10914,6 +11294,9 @@ \subsection{Thread-safety in multithreaded user applications} \label{sec:threads} %---------------------------------------- +% TODO in 4.0: this entire section will likely be deleted, with the +% pending change to GrB_wait and GrB_error. + SuiteSparse:GraphBLAS is parallel, based on OpenMP. It is thread-safe if multiple simultaneous calls are made to GraphBLAS functions, from user threads that rely on either OpenMP or POSIX pthreads. The output variables of those @@ -10921,21 +11304,27 @@ \subsection{Thread-safety in multithreaded user applications} object in parallel, with two or more simultaneous GraphBLAS functions operating on the same output object. In addition, all pending operations of objects that appear in parallel calls to GraphBLAS must be complete. This can be done for -all objects via \verb'GrB_wait', or it can be done by calling a method or -operation that forces completion of a particular object (such as -\verb'GrB_*_nvals'). If multiple parallel calls to GraphBLAS functions operate -on unique inputs, then those input objects can safely have pending operations. - -To use GraphBLAS from a multithreaded user application, GraphBLAS -requires access to a critical section for the \verb'GrB_wait' queue of -matrices with pending operations, and to a thread-local storage space -so that each user thread can safely retrieve its own error message with -\verb'GrB_error'. +all objects via \verb'GrB_Matrix_wait', \verb'GrB_Vector_wait', and +\verb'GxB_Scalar_wait', which force completion of a particular object. If +multiple parallel calls to GraphBLAS functions operate on unique inputs, then +those input objects can safely have pending operations. + +% TODO in 4.0: delete this for V4.0 when GrB_wait is removed: +{\bf NOTE: the following will no longer be required in a future version, +when \verb'GrB_wait()' is removed.} + +To use GraphBLAS from a multithreaded user application, GraphBLAS requires +access to a critical section for the (now deprecated) \verb'GrB_wait()' queue +of matrices with pending operations, and to a thread-local storage space so +that each user thread can safely retrieve its own error message with +\verb'GrB_error'. In v4.0, the no-argument \verb'GrB_wait()' function will be +removed, and thus the user-thread-based critical section will be no longer +needed. SuiteSparse:GraphBLAS supports the following user threading models. By default, the \verb'cmake' script detects the presence of OpenMP and POSIX pthreads. If OpenMP is present, it uses OpenMP critical sections for -\verb'GrB_wait' and OpenMP \verb'threadprivate(...)' for thread-local storage +\verb'GrB_wait()' and OpenMP \verb'threadprivate(...)' for thread-local storage for \verb'GrB_error'. Otherwise, if POSIX pthreads are available, it uses a POSIX \verb'mutex', and POSIX thread-local storage via \verb'pthread_key_create'. @@ -10971,14 +11360,6 @@ \subsection{Thread-safety in multithreaded user applications} \end{itemize} -The following user-threading models are not yet supported, but may be in -a future version. - -\begin{itemize} -\item Microsoft Windows: \verb'cmake -DUSER_WINDOWS=1' -\item ANSI C11 threads: \verb'cmake -DUSER_ANSI=1' -\end{itemize} - %---------------------------------------- \subsection{Default matrix format} %---------------------------------------- @@ -11040,7 +11421,7 @@ \subsection{Setting the C flags and using CMake} endif ( ) \end{verbatim} } -To compile SuiteSparse:GraphBLAS without running the demos, use +To compile SuiteSparse:GraphBLAS without running the demos, use \newline \verb'make library' in the top-level directory, or \verb'make' in the \verb'build' directory. @@ -11048,13 +11429,29 @@ \subsection{Setting the C flags and using CMake} file, but these are meant only for code development of SuiteSparse:GraphBLAS itself, not for end-users of SuiteSparse:GraphBLAS. +One particularly useful option is the \verb'BURBLE' setting. It must be +enabled both at compile time and then at run time with \verb'GxB_set' +\verb'(GxB_BURBLE, true)', or \verb'GrB.burble(1)' in the MATLAB interface. If +enabled, SuiteSparse:GraphBLAS will print out a report as to which internal +kernels it uses, and how much time is spent. If you see the word +\verb'generic', it means that SuiteSparse:GraphBLAS was unable to use is faster +kernels in \verb'Source/Generated', but used a generic kernel that relies on +function pointers. This is done for user-defined types and operators, and when +typecasting is performed, and it is typically slower than the kernels in +\verb'Source/Generated'. If you see a lot of \verb'wait' statements, it may +mean that a lot of time is spent finishing a matrix or vector. This may be +the result of an inefficient use of the \verb'setElement' and \verb'assign' +methods. + %---------------------------------------- \subsection{Using a plain makefile} %---------------------------------------- The \verb'GraphBLAS/alternative' directory contains a simple \verb'Makefile' that can be used to compile SuiteSparse:GraphBLAS. This is a useful option -if you do not have the required version of \verb'cmake'. +if you do not have the required version of \verb'cmake'. This \verb'Makefile' +can even compile the entire library with a C++ compiler, which cannot be +done with \verb'CMake'. %---------------------------------------- \subsection{Running the Demos} @@ -11088,11 +11485,17 @@ \subsection{Installing SuiteSparse:GraphBLAS} \subsection{Running the tests} %---------------------------------------- +To run a short test, type \verb'make run' at the top-level \verb'GraphBLAS' +folder. This will run all the demos in \verb'GraphBLAS/Demos'. MATLAB is not +required. + To perform the extensive tests in the \verb'Test' folder, and the statement coverage tests in \verb'Tcov', MATLAB R2017A is required. See the \verb'README.txt' files in those two folders for instructions on how to run the tests. The tests in the \verb'Test' folder have been ported to MATLAB on -Linux, MacOS, and Windows. The \verb'Tcov' tests do not work on Windows. +Linux, MacOS, and Windows. The \verb'Tcov' tests do not work on Windows. The +MATLAB interface test (\verb'gbtest') works on all platforms; see the +\verb'GraphBLAS/GraphBLAS' folder for more details. %---------------------------------------- \subsection{Cleaning up} @@ -11145,17 +11548,16 @@ \section{Acknowledgments} for his help in porting GraphBLAS to Microsoft Windows. SuiteSparse:GraphBLAS was developed with support from -NVIDIA, MIT Lincoln Lab, Intel, Redis Labs, IBM, -and the National Science Foundation (1514406). +NVIDIA, Intel, MIT Lincoln Lab, Redis Labs, IBM, +and the National Science Foundation (1514406, 1835499). %------------------------------------------------------------------------------- \section{Additional Resources} %------------------------------------------------------------------------------- -See \url{http://graphblas.org} for the GraphBLAS community page. -See -\url{https://github.com/szarnyasg/graphblas-pointers} for an up-to-date list -of additional resources on GraphBLAS. +See \url{http://graphblas.org} for the GraphBLAS community page. See +\url{https://github.com/GraphBLAS/GraphBLAS-Pointers} for an up-to-date list of +additional resources on GraphBLAS, maintained by G{\'{a}}bor Sz{\'{a}}rnyas. \newpage %------------------------------------------------------------------------------- diff --git a/Doc/GraphBLAS_version.tex b/Doc/GraphBLAS_version.tex index 33bd472eb2..e4693a1db1 100644 --- a/Doc/GraphBLAS_version.tex +++ b/Doc/GraphBLAS_version.tex @@ -1,5 +1,5 @@ % version of SuiteSparse:GraphBLAS \date{VERSION -3.2.2, -Apr 2, 2020} +3.3.0, +June 26, 2020} diff --git a/Doc/HPEC20_Python_and_MATLAB.pdf b/Doc/HPEC20_Python_and_MATLAB.pdf new file mode 100644 index 0000000000..68539b1965 Binary files /dev/null and b/Doc/HPEC20_Python_and_MATLAB.pdf differ diff --git a/Doc/README_Doc.txt b/Doc/README_Doc.txt index 29826dd41b..a0d8ceb21b 100644 --- a/Doc/README_Doc.txt +++ b/Doc/README_Doc.txt @@ -6,7 +6,7 @@ This folder contains the following files: CONTRIBUTOR-LICENSE.txt how to contribute to GraphBLAS ChangeLog changes in GraphBLAS - GraphBLAS_API_C.pdf the GraphBLAS C API Specification + GraphBLAS_API_C_v13.pdf the GraphBLAS C API Specification GraphBLAS_API_version.tex the version of the C API that this version of SuiteSparse:GraphBLAS conforms to. GraphBLAS_UserGuide.pdf the SuiteSparse:GraphBLAS User Guide @@ -27,6 +27,8 @@ Papers on SuiteSparse:GraphBLAS. See the User Guide for the full citations. Davis_HPEC18.pdf "Graph algorithms via SuiteSparse:GraphBLAS..." lagraph-grapl19.pdf "LAGraph: a community effort to collect graph algorithms built on top of the GraphBLAS" + HPEC20_Python_and_MATLAB.pdf "GraphBLAS programmability", by Mattson + Pelletier, and Davis. submitted to HPEC'20 Additional installation notes are below. diff --git a/GraphBLAS/@GrB/GrB.m b/GraphBLAS/@GrB/GrB.m index a8617b062a..23e2f84a51 100644 --- a/GraphBLAS/@GrB/GrB.m +++ b/GraphBLAS/@GrB/GrB.m @@ -3,14 +3,17 @@ % % GraphBLAS is a library for creating graph algorithms based on sparse % linear algebraic operations over semirings. Visit http://graphblas.org -% for more details and resources. See also the SuiteSparse:GraphBLAS -% User Guide in this package. +% for more details and resources. See also the SuiteSparse:GraphBLAS User +% Guide in this package. % % The MATLAB GrB class represents a GraphBLAS sparse matrix. The GrB % method creates a GraphBLAS sparse matrix from a MATLAB matrix. Other -% methods also generate GrB matrices. For example G = GrB.subassign (C, -% M, A) constructs a GraphBLAS matrix G, which is the result of C=A in -% GraphBLAS notation (like C(M)=A(M) in MATLAB). The matrices used any +% methods also generate GrB matrices. For example: +% +% G = GrB.subassign (C, M, A) ; +% +% constructs a GraphBLAS matrix G, which is the result of C=A in +% GraphBLAS notation (like C(M)=A(M) in MATLAB). The matrices used in any % GrB.method may be MATLAB matrices (sparse or dense) or GraphBLAS sparse % matrices, in any combination. % @@ -44,22 +47,27 @@ % -------------------- % Matrix types: % -------------------- -% +% % Most of the valid type strings correspond to MATLAB class of the same % name (see 'help class'): % -% 'double' 64-bit floating-point (real, not complex) -% 'single' 32-bit floating-point (real, not complex) -% 'logical' 8-bit boolean -% 'int8' 8-bit signed integer -% 'int16' 16-bit signed integer -% 'int32' 32-bit signed integer -% 'int64' 64-bit signed integer -% 'uint8' 8-bit unsigned integer -% 'uint16' 16-bit unsigned integer -% 'uint32' 32-bit unsigned integer -% 'uint64' 64-bit unsigned integer -% 'complex' 64-bit double complex (not yet implemented). +% 'logical' 8-bit boolean +% 'int8' 8-bit signed integer +% 'int16' 16-bit signed integer +% 'int32' 32-bit signed integer +% 'int64' 64-bit signed integer +% 'uint8' 8-bit unsigned integer +% 'uint16' 16-bit unsigned integer +% 'uint32' 32-bit unsigned integer +% 'uint64' 64-bit unsigned integer +% 'double' 64-bit floating-point (real, not complex) +% 'single' 32-bit floating-point (real, not complex) +% 'single complex' single complex +% 'double complex' double complex (also just 'complex') +% +% In MATLAB matrices, complex is an attribute, not a class. In GrB +% matrices, 'double complex' and 'single complex' are treated as their +% own data types. % % --------------- % Matrix formats: @@ -67,20 +75,20 @@ % % The format of a GraphBLAS matrix can have a large impact on % performance. GraphBLAS matrices can be stored by column or by row. -% The corresponding format string is 'by col' or 'by row', -% respectively. Since the only format that MATLAB supports for its -% sparse and full matrices is 'by col', that is the default format for -% GraphBLAS matrices via this MATLAB interfance. However, the default -% for the C API is 'by row' since graph algorithms tend to be faster -% with that format. +% The corresponding format string is 'by col' or 'by row', respectively. +% Since the only format that MATLAB supports for its sparse and full +% matrices is 'by col', that is the default format for GraphBLAS +% matrices via this MATLAB interfance. However, the default for the C +% API is 'by row' since graph algorithms tend to be faster with that +% format. % % Column vectors are always stored 'by col', and row vectors are always % stored 'by row'. The format for new matrices propagates from the % format of their inputs. For example with C=A*B, C takes on the same -% format as A, unless A is a vector, in which case C takes on the -% format of B. If both A and B are vectors, then the format of C is -% determined by the descriptor (if present), or by the default format -% (see GrB.format). +% format as A, unless A is a vector, in which case C takes on the format +% of B. If both A and B are vectors, then the format of C is determined +% by the descriptor (if present), or by the default format (see +% GrB.format). % % When a GraphBLAS matrix is converted into a MATLAB sparse or full % matrix, it is always returned to MATLAB 'by col'. @@ -90,143 +98,217 @@ %-------------------- % % Operations on integer values differ from MATLAB. In MATLAB, -% uint9(255)+1 is 255, since the arithmetic saturates. This is not +% uint8(255)+1 is 255, since the arithmetic saturates. This is not % possible in matrix operations such as C=A*B, since saturation of % integer arithmetic would render most of the monoids useless. % GraphBLAS instead computes a result modulo the word size, so that % GrB(uint8(255))+1 is zero. However, new unary and binary operators % could be added so that element-wise operations saturate. The C % interface allows for arbitrary creation of user-defined operators, so -% this could be added in the future. +% this could be added in the future. See 'help GrB/MATLAB_vs_GrB' for +% more details. % %------------------------------------------------------------------------- % Methods for the GrB class: %------------------------------------------------------------------------- % -% These methods operate on GraphBLAS matrices only, and they overload -% the existing MATLAB functions of the same name. -% % C = GrB (...) construct a GraphBLAS matrix -% C = sparse (G) makes a copy of a GrB matrix -% C = full (G, ...) adds explicit zeros or id values -% C = double (G) cast GrB matrix to MATLAB sparse double -% C = logical (G) cast GrB matrix to MATLAB sparse logical +% +% Overloaded MATLAB operators (all except 'colon'): +% +% C = and (A, B) C = A & B +% C = ctranspose (G) C = G' +% i = end (G, k, ndims) A(1:end,1:end) +% C = eq (A, B) C = A == B +% C = ge (A, B) C = A >= B +% C = gt (A, B) C = A > B +% C = horzcat (A, B) C = [A , B] +% C = ldivide (A, B) C = A .\ B +% C = le (A, B) C = A <= B +% C = lt (A, B) C = A < B +% C = minus (A, B) C = A - B +% C = mldivide (A, B) C = A \ B +% C = mpower (A, B) C = A ^ B +% C = mrdivide (A, B) C = A / B +% C = mtimes (A, B) C = A * B +% C = ne (A, B) C = A ~= B +% C = not (G) C = ~G +% C = or (A, B) C = A | B +% C = plus (A, B) C = A + B +% C = power (A, B) C = A .^ B +% C = rdivide (A, B) C = A ./ B +% I = subsindex (G) X = A (G) +% C = subsasgn (C, S, A) C (I,J) = A or C (M) = A +% C = subsref (A, S) C = A (I,J) or C = A (M) +% C = times (A, B) C = A .* B +% C = transpose (G) C = G.' +% C = uminus (G) C = -G +% C = uplus (G) C = +G +% C = vertcat (A, B) C = [A ; B] +% +% Overloaded MATLAB functions: +% +% C = abs (G) absolute value +% C = acos (G) inverse cosine +% C = acosh (G) inverse hyperbolic cosine +% C = acot (G) inverse cotangent +% C = acoth (G) inverse hyperbolic cotangent +% C = acsc (G) inverse cosecant +% C = acsch (G) inverse hyperbolic cosecant +% C = all (G, ...) reduce via '&', to vector or scalar +% p = amd (G, ...) approximate minimum degree ordering +% C = angle (G) phase angle of a complex matrix +% C = any (G, ...) reduce via '|', to vector or scalar +% C = asec (G) inverse secant +% C = asech (G) inverse hyperbolic secant +% C = asin (G) inverse sine +% C = asinh (G) inverse hyperbolic sine +% assert (G) generate an error if G is false +% C = atan (G) inverse tangent +% C = atanh (G) inverse hyperbolic tangent +% C = atan2 (A, B) inverse tangent (four-quadrant) +% +% [lo, hi] = bandwidth (G, ...) lower and upper bandwidth of G +% C = bitand (A, B, ...) bitwise and +% C = bitcmp (A, ...) bitwise negation +% C = bitget (A, B, ...) get bits +% C = bitset (A, B, ...) set bits +% C = bitshift (A, B, ...) shift bits +% C = bitor (A, B, ...) bitwise or +% C = bitxor (A, B, ...) bitwise xor +% +% C = cast (G, ...) cast GrB matrix to MATLAB matrix +% C = ceil (G) round towards infinity +% p = colamd (G) column approximate minimum degree ordering % C = complex (G) cast GrB matrix to MATLAB sparse complex -% C = single (G) cast GrB matrix to MATLAB full single +% C = conj (G) complex conjugate +% C = cos (G) cosine +% C = cosh (G) hyperbolic cosine +% C = cot (G) cotangent +% C = coth (G) hyperbolic cotangent +% C = csc (G) cosecant +% C = csch (G) hyperbolic cosecant +% +% C = diag (A, k) diagonal matrices and diagonals +% DiGraph = digraph (G,...) directed Graph +% disp (A, level) display a MATLAB or GrB matrix A +% display (G) display a GrB matrix G; same as disp(G,2) +% [...] = dmperm (G) Dulmage-Mendelsohn permutation +% C = double (G) cast GrB matrix to MATLAB sparse double +% +% [V, ...] = eig (G,...) eigenvalues and eigenvectors +% G = GrB.empty (m, n) empty matrix for the GrB class +% C = eps (G) floating-point spacing +% C = erf (G) error function +% C = erfc (G) complementary error function +% p = etree (G) elimination tree +% C = exp (G) natural exponent +% C = expm1 (G) exp (x) - 1 +% +% C = false (...) all-false logical matrix +% [I,J,X] = find (G, ...) extract entries from a matrix +% C = fix (G) round towards zero +% C = flip (G, dim) flip the order of entries +% C = floor (G) round towards -infinity +% c = fprintf (...) print to a file or to the Command Window +% C = full (G, ...) adds explicit zeros or id values +% +% C = gamma (G) gamma function +% C = gammaln (G) logarithm of gamma function +% Graph = graph (G, ...) undirected graph +% +% C = hypot (A, B) sqrt of sum of squares +% +% C = imag (G) imaginary part of a complex matrix % C = int8 (G) cast GrB matrix to MATLAB full int8 % C = int16 (G) cast GrB matrix to MATLAB full int16 % C = int32 (G) cast GrB matrix to MATLAB full int32 % C = int64 (G) cast GrB matrix to MATLAB full int64 -% C = uint8 (G) cast GrB matrix to MATLAB full uint8 -% C = uint16 (G) cast GrB matrix to MATLAB full uint16 -% C = uint32 (G) cast GrB matrix to MATLAB full uint32 -% C = uint64 (G) cast GrB matrix to MATLAB full uint64 -% C = cast (G,...) cast GrB matrix to MATLAB matrix (as above) -% X = nonzeros (G) extract all entries from a GrB matrix -% [I,J,X] = find (G,...) extract all entries from a GrB matrix -% C = spones (G) return pattern of GrB matrix -% disp (G, level) display a GrB matrix G -% display (G) display a GrB matrix G; same as disp(G,2) -% mn = numel (G) m*n for an m-by-n GrB matrix G -% e = nnz (G) number of entries in a GrB matrix G -% e = nzmax (G) number of entries in a GrB matrix G -% [m n] = size (G) size of a GrB matrix G -% n = length (G) length of a GrB vector -% s = isempty (G) true if any dimension of G is zero -% s = issparse (G) true for any GrB matrix G -% s = ismatrix (G) true for any GrB matrix G -% s = isvector (G) true if m=1 or n=1, for an m-by-n GrB matrix G +% s = isa (G, classname) check if a GrB matrix is of a specific class +% s = isbanded (G,...) true if G is banded % s = iscolumn (G) true if n=1, for an m-by-n GrB matrix G -% s = isrow (G) true if m=1, for an m-by-n GrB matrix G -% s = isscalar (G) true if G is a 1-by-1 GrB matrix -% s = isnumeric (G) true for any GrB matrix G (even logical) +% s = isdiag (G) true if G is diagonal +% s = isempty (G) true if any dimension of G is zero +% s = isequal (A, B) test if equal +% C = isfinite (G) test if finite % s = isfloat (G) true if GrB matrix is double, single, complex -% s = isreal (G) true if GrB matrix is not complex +% s = ishermitian (G) true if G is Hermitian +% C = isinf (G) test if infinite % s = isinteger (G) true if GrB matrix is int8, int16, ..., uint64 % s = islogical (G) true if GrB matrix is logical -% s = isa (G, classname) check if a GrB matrix is of a specific class -% C = diag (G,k) diagonal matrices and diagonals -% L = tril (G,k) lower triangular part of GrB matrix G -% U = triu (G,k) upper triangular part of GrB matrix G -% C = kron (A,B) Kronecker product -% C = repmat (G, ...) replicate and tile a GraphBLAS matrix -% C = reshape (G, ...) reshape a GraphBLAS matrix -% C = abs (G) absolute value -% C = sign (G) signum function +% s = ismatrix (G) true for any GrB matrix G +% C = isnan (G) test if NaN +% s = isnumeric (G) true for any GrB matrix G (even logical) +% s = isreal (G) true if GrB matrix is not complex +% s = isrow (G) true if m=1, for an m-by-n GrB matrix G +% s = isscalar (G) true if G is a 1-by-1 GrB matrix +% s = issparse (G) true for any GrB matrix G +% s = issymmetric (G) true if G is symmetric % s = istril (G) true if G is lower triangular % s = istriu (G) true if G is upper triangular -% s = isbanded (G,...) true if G is banded -% s = isdiag (G) true if G is diagonal -% s = ishermitian (G) true if G is Hermitian -% s = issymmetric (G) true if G is symmetric -% [lo,hi] = bandwidth (G) determine the lower & upper bandwidth of G -% C = sum (G, option) reduce via sum, to vector or scalar -% C = prod (G, option) reduce via product, to vector or scalar +% s = isvector (G) true if m=1 or n=1, for an m-by-n GrB matrix G +% +% C = kron (A, B) Kronecker product +% +% n = length (G) length of a GrB vector +% C = log (G) natural logarithm +% C = log10 (G) base-10 logarithm +% C = log1p (G) log (1+x) +% [F, E] = log2 (G) base-2 logarithm +% C = logical (G) cast GrB matrix to MATLAB sparse logical +% +% C = max (A,B,option) reduce via max, to vector or scalar +% C = min (A,B,option) reduce via min, to vector or scalar +% +% e = nnz (G) number of entries in a GrB matrix G +% X = nonzeros (G) extract all entries from a GrB matrix % s = norm (G, kind) norm of a GrB matrix -% [C,I] = max (G, ...) reduce via max, to vector or scalar -% C = min (G, ...) reduce via min, to vector or scalar -% C = any (G, ...) reduce via '|', to vector or scalar -% C = all (G, ...) reduce via '&', to vector or scalar -% C = sqrt (G) element-wise square root -% C = eps (G) floating-point spacing -% C = ceil (G) round towards infinity -% C = floor (G) round towards -infinity +% e = numel (G) m*n for an m-by-n GrB matrix G +% e = nzmax (G) number of entries in a GrB matrix G +% +% C = ones (...) matrix with all ones, same type as G +% +% C = pow2 (F, E) base-2 power +% C = prod (G, option) reduce via product, to vector or scalar +% +% C = real (G) real part of a complex matrix +% C = repmat (G, ...) replicate and tile a GraphBLAS matrix +% C = reshape (G, ...) reshape a GraphBLAS matrix % C = round (G) round towards nearest -% C = fix (G) round towards zero -% C = isfinite (G) test if finite -% C = isinf (G) test if infinite -% C = isnan (G) test if NaN +% +% C = sec (G) secant +% C = sech (G) hyperbolic secant +% C = sign (G) signum function +% C = sin (G) sine +% C = single (G) cast GrB matrix to MATLAB full single +% C = sinh (G) hyperbolic sine +% [m,n,t] = size (G,dim) size and type of a GrB matrix +% C = sparse (G) makes a copy of a GrB matrix % C = spfun (fun, G) evaluate a function on the entries of G -% p = amd (G) approximate minimum degree ordering -% p = colamd (G) column approximate minimum degree ordering +% C = spones (G, type) return pattern of GrB matrix +% C = sprand (...) random GraphBLAS matrix +% C = sprandn (...) random GraphBLAS matrix, normal distribution +% C = sprandsym (...) random symmetric GraphBLAS matrix +% c = sprintf (...) print to a string +% C = sqrt (G) element-wise square root +% C = sum (G, option) reduce via sum, to vector or scalar % p = symamd (G) approximate minimum degree ordering % p = symrcm (G) reverse Cuthill-McKee ordering -% [...] = dmperm (G) Dulmage-Mendelsohn permutation -% parent = etree (G) elimination tree -% C = conj (G) complex conjugate -% C = real (G) real part of a complex GraphBLAS matrix -% [V, ...] = eig (G,...) eigenvalues and eigenvectors -% assert (G) generate an error if G is false -% C = zeros (...,'like',G) all-zero matrix, same type as G -% C = false (...,'like',G) all-false logical matrix -% C = ones (...,'like',G) matrix with all ones, same type as G -% c = fprintf (...) print to a file or to the Command Window -% c = sprintf (...) print to a string -% C = flip (G, dim) flip the order of entries -% C = sprand (G) random GraphBLAS matrix -% C = sprandn (G) random GraphBLAS matrix, normal distribution -% C = sprandsym (G, ...) random symmetric GraphBLAS matrix % -% operator overloading: +% C = tan (G) tangent +% C = tanh (G) hyperbolic tangent +% L = tril (G, k) lower triangular part of GrB matrix G +% U = triu (G, k) upper triangular part of GrB matrix G +% C = true (...) all-true logical matrix % -% C = plus (A, B) C = A + B -% C = minus (A, B) C = A - B -% C = uminus (G) C = -G -% C = uplus (G) C = +G -% C = times (A, B) C = A .* B -% C = mtimes (A, B) C = A * B -% C = rdivide (A, B) C = A ./ B -% C = ldivide (A, B) C = A .\ B -% C = mrdivide (A, B) C = A / B -% C = mldivide (A, B) C = A \ B -% C = power (A, B) C = A .^ B -% C = mpower (A, B) C = A ^ B -% C = lt (A, B) C = A < B -% C = gt (A, B) C = A > B -% C = le (A, B) C = A <= B -% C = ge (A, B) C = A >= B -% C = ne (A, B) C = A ~= B -% C = eq (A, B) C = A == B -% C = and (A, B) C = A & B -% C = or (A, B) C = A | B -% C = not (G) C = ~G -% C = ctranspose (G) C = G' -% C = transpose (G) C = G.' -% C = horzcat (A, B) C = [A , B] -% C = vertcat (A, B) C = [A ; B] -% C = subsref (A, I, J) C = A (I,J) or C = A (M) -% C = subsasgn (A, I, J) C (I,J) = A -% index = end (A, k, n) for object indexing, A(1:end,1:end) +% C = uint8 (G) cast GrB matrix to MATLAB full uint8 +% C = uint16 (G) cast GrB matrix to MATLAB full uint16 +% C = uint32 (G) cast GrB matrix to MATLAB full uint32 +% C = uint64 (G) cast GrB matrix to MATLAB full uint64 +% +% C = xor (A, B) exclusive or +% +% C = zeros (...) all-zero matrix, same type as G % %------------------------------------------------------------------------- % Static Methods: @@ -234,7 +316,7 @@ % % The Static Methods for the GrB class can be used on input matrices of % any kind: GraphBLAS sparse matrices, MATLAB sparse matrices, or -% MATLAB dense matrices, in any combination. The output matrix Cout is +% MATLAB dense matrices, in any combination. The output matrix C is % a GraphBLAS matrix, by default, but can be optionally returned as a % MATLAB sparse or dense matrix. The static methods divide into three % categories: those that perform basic functions, graph algorithms, @@ -244,52 +326,55 @@ % GraphBLAS basic functions: %--------------------------- % -% GrB.init initialize GraphBLAS -% GrB.finalize finish GraphBLAS +% context: % GrB.clear clear GraphBLAS workspace and settings -% GrB.descriptorinfo (d) list properties of a descriptor -% GrB.unopinfo (op, type) list properties of a unary operator -% GrB.binopinfo (op, type) list properties of a binary operator -% GrB.monoidinfo (op, type) list properties of a monoid -% GrB.semiringinfo (s, type) list properties of a semiring -% GrB.selectopinfo (op) list properties of a select operator +% GrB.finalize finish GraphBLAS +% GrB.init initialize GraphBLAS % t = GrB.threads (t) set/get # of threads to use in GraphBLAS % c = GrB.chunk (c) set/get chunk size to use in GraphBLAS % b = GrB.burble (b) set/get burble (diagnostic output) -% result = GrB.entries (G,...) count or query entries in a matrix -% result = GrB.nonz (G,...) count or query nonzeros in a matrix -% C = GrB.prune (A, id) prune entries equal to id -% C = GrB.offdiag (A) prune diagonal entries -% s = GrB.isfull (A) true if all entries present +% +% info: +% GrB.binopinfo (op, type) list properties of a binary operator +% GrB.descriptorinfo (d) list properties of a descriptor +% GrB.monoidinfo (op, type) list properties of a monoid +% GrB.selectopinfo (op) list properties of a select operator +% GrB.semiringinfo (s, type) list properties of a semiring +% GrB.unopinfo (op, type) list properties of a unary operator +% +% operations: +% C = GrB.build (I,J,X,m,n,dup,type,desc) build a GrB matrix from +% list of entries (like C=sparse(I,J,X...)) % [C,I,J] = GrB.compact (A,id) remove empty rows and columns -% G = GrB.empty (m, n) return an empty GraphBLAS matrix -% s = GrB.type (A) get the type of a MATLAB or GrB matrix A -% s = GrB.issigned (type) true if type is signed -% f = GrB.format (f) set/get matrix format to use in GraphBLAS +% c = GrB.entries (A,...) count or query entries in a matrix +% C = GrB.expand (scalar, A) expand a scalar (C = scalar*spones(A)) +% [I,J,X] = GrB.extracttuples (A,desc) extract all entries (like 'find') +% C = GrB.eye (m,n,type) identity matrix of any type (like 'speye') +% f = GrB.format (f) set/get matrix format by row or col % s = GrB.isbyrow (A) true if format f A is 'by row' % s = GrB.isbycol (A) true if format f A is 'by col' -% C = GrB.expand (scalar, A) expand a scalar (C = scalar*spones(A)) -% C = GrB.eye identity matrix of any type -% C = GrB.speye identity matrix (of type 'double') -% C = GrB.random (varargin) random GraphBLAS matrix -% C = GrB.build (I, J, X, m, n, dup, type, desc) -% build a GrB matrix from list of entries -% [I,J,X] = GrB.extracttuples (A, desc) -% extract all entries from a matrix -% s = GrB.normdiff (A, B, kind) norm (A-B,kind) +% s = GrB.isfull (A) true if all entries present +% s = GrB.issigned (type) true if type is signed +% c = GrB.nonz (A,...) count or query nonzeros in a matrix +% s = GrB.normdiff (A,B,kind) norm (A-B,kind) +% C = GrB.offdiag (A) prune diagonal entries +% C = GrB.prune (A, id) prune entries equal to id +% C = GrB.random (...) random GraphBLAS matrix (like 'sprand') +% C = GrB.speye (m,n,type) identity matrix of any type (like 'speye') +% t = GrB.type (A) get the type of a MATLAB or GrB matrix A % %------------------------------------- % Static Methods for graph algorithms: %------------------------------------- % -% r = GrB.pagerank (A, opts) ; PageRank of a matrix +% [v, parent] = GrB.bfs (A, s, ...) ; breadth-first search +% Y = GrB.dnn (W, bias, Y0) ; deep neural network +% C = GrB.incidence (A, ...) ; incidence matrix % C = GrB.ktruss (A, k, check) ; k-truss -% s = GrB.tricount (A, check) ; triangle count % L = GrB.laplacian (A, type, check) ; Laplacian graph -% C = GrB.incidence (A, ...) ; incidence matrix -% [v, parent] = GrB.bfs (A, s, ...) ; breadth-first search % iset = GrB.mis (A, check) ; maximal independent set -% Y = GrB.dnn (W, bias, Y0) ; deep neural network +% r = GrB.pagerank (A, opts) ; PageRank of a matrix +% s = GrB.tricount (A, check) ; triangle count % %----------------------------------- % Foundational GraphBLAS operations: @@ -298,38 +383,39 @@ % GraphBLAS has 12 foundational operations, listed below. All have % similar parameters. The full set of input parameters is listed in % the order in which they appear in the GraphBLAS C API, except that -% for the MATLAB interface, Cin and Cout are different matrices. They +% for the MATLAB interface, Cin and C are different matrices. They % combine into a single input/output matrix in the GraphBLAS C API. In % the MATLAB interface, many of the parameters become optional, and % they can appear in different order. % -% GrB.mxm sparse matrix-matrix multiplication over a semiring -% GrB.kronecker Kronecker product +% GrB.apply apply a unary operator +% GrB.apply2 apply a binary operator +% GrB.assign sparse matrix assignment, such as C(I,J)=A % GrB.eadd element-wise addition % GrB.emult element-wise multiplication +% GrB.extract extract submatrix, like C=A(I,J) in MATLAB +% GrB.kronecker Kronecker product +% GrB.mxm sparse matrix-matrix multiplication over a semiring +% GrB.reduce reduce a matrix to a scalar % GrB.select select a subset of entries from a matrix -% GrB.vreduce reduce a matrix to a vector -% GrB.apply apply a unary operator -% GrB.assign sparse matrix assignment, such as C(I,J)=A % GrB.subassign sparse matrix assignment, such as C(I,J)=A -% GrB.extract extract submatrix, like C=A(I,J) in MATLAB % GrB.trans transpose a matrix -% GrB.reduce reduce a matrix to a scalar +% GrB.vreduce reduce a matrix to a vector % -% In GraphBLAS notation (with Cout, Cin arguments for the one matrix +% In GraphBLAS notation (with C, Cin arguments for the one matrix % C), these take the following form: % % C<#M,replace> = accum (C, operation (A or A', B or B')) % % C is both an input and output matrix. In this MATLAB interface to -% GraphBLAS, it is split into Cin (the value of C on input) and Cout +% GraphBLAS, it is split into Cin (the value of C on input) and C % (the value of C on output). M is the optional mask matrix, and #M is % either M or ~M depending on whether or not the mask is complemented % via the desc.mask option. The replace option is determined by % desc.out; if present, C is cleared after it is used in the accum % operation but before the final assignment. A and/or B may optionally % be transposed via the descriptor fields desc.in0 and desc.in1, -% respectively. To select the format of Cout, use desc.format. See +% respectively. To select the format of C, use desc.format. See % GrB.descriptorinfo for more details. % % accum is optional; if not is not present, then the operation becomes @@ -344,18 +430,19 @@ % % The full list of parameters is shown below: % -% Cout = GrB.mxm (Cin, M, accum, op, A, B, desc) -% Cout = GrB.kronecker (Cin, M, accum, op, A, B, desc) -% Cout = GrB.eadd (Cin, M, accum, op, A, B, desc) -% Cout = GrB.emult (Cin, M, accum, op, A, B, desc) -% Cout = GrB.select (Cin, M, accum, op, A, b, desc) -% Cout = GrB.vreduce (Cin, M, accum, op, A, desc) -% Cout = GrB.apply (Cin, M, accum, op, A, desc) -% Cout = GrB.assign (Cin, M, accum, A, I, J, desc) -% Cout = GrB.subassign (Cin, M, accum, A, I, J, desc) -% Cout = GrB.extract (Cin, M, accum, A, I, J, desc) -% Cout = GrB.trans (Cin, M, accum, A, desc) -% Cout = GrB.reduce (Cin, accum, op, A, desc) +% C = GrB.apply (Cin, M, accum, op, A, desc) +% C = GrB.apply2 (Cin, M, accum, op, A, B, desc) +% C = GrB.assign (Cin, M, accum, A, I, J, desc) +% C = GrB.eadd (Cin, M, accum, op, A, B, desc) +% C = GrB.emult (Cin, M, accum, op, A, B, desc) +% C = GrB.extract (Cin, M, accum, A, I, J, desc) +% C = GrB.kronecker (Cin, M, accum, op, A, B, desc) +% C = GrB.mxm (Cin, M, accum, op, A, B, desc) +% C = GrB.reduce (Cin, accum, op, A, desc) +% C = GrB.select (Cin, M, accum, op, A, b, desc) +% C = GrB.subassign (Cin, M, accum, A, I, J, desc) +% C = GrB.trans (Cin, M, accum, A, desc) +% C = GrB.vreduce (Cin, M, accum, op, A, desc) % % The parameters divide into 4 classes: matrices, strings, cells, and a % single optional struct (the descriptor). The order of parameters @@ -367,11 +454,12 @@ % % (1) Cin, M, A, B are matrices. If the method takes up to 4 matrices % (mxm, kronecker, select (with operator requiring a b -% parameter), eadd, emult), then they appear in this order: +% parameter), eadd, emult, apply2), then they appear in this order: % with 2 matrix inputs: A, B % with 3 matrix inputs: Cin, A, B % with 4 matrix inputs: Cin, M, A, B -% For the GrB.select, b is a scalar. +% For GrB.select, b is a scalar. For GrB.apply2, either A or B +% is be a scalar. % % If the method takes up to 3 matrices (vreduce, apply, assign, % subassign, extract, trans, or select without b): @@ -420,16 +508,8 @@ % strings '+' and '+.*' must appear in that order, but the matrices and % strings may be interleaved arbitrarily. % -% C = GrB.mxm (C, M, '+', '+.*', A, B) C += A*B -% C = GrB.mxm (C, M, '+', A, '+.*', B) C += A*B -% C = GrB.mxm ('+', '+,*', C, M, A, B) C += A*B -% -% C = GrB.mxm ('+.*', A, B) C = A*B -% C = GrB.mxm (A, '+.*', B) C = A*B -% C = GrB.mxm (C, M, A, '+.*', B) C = A*B -% -% C = GrB.emult (C, M, '+', A, '*', B) C += A.*B -% C = GrB.emult (A, '*', B) C = A.*B +% C = GrB.apply (C, M, '|', '~', A) C |= ~A +% C = GrB.apply ('~', A) C = ~A % % C = GrB.assign (C, M, '+', A, I, J) C(I,J) += A % C = GrB.assign (C, I, J, M, '+', A) C(I,J) += A @@ -441,6 +521,9 @@ % C = GrB.assign (C, M, '+', A) C += A % C = GrB.assign (C, '+', A, I) C (I,:) += A % +% C = GrB.emult (C, M, '+', A, '*', B) C += A.*B +% C = GrB.emult (A, '*', B) C = A.*B +% % C = GrB.extract (C, M, '+', A, I, J) C += A(I,J) % C = GrB.extract (A, I, J) C = A(I,J) % C = GrB.extract (I, J, A) C = A(I,J) @@ -449,8 +532,13 @@ % C = GrB.extract (C, M, '+', A) C += A % C = GrB.extract (C, '+', A, I) C += A(I,:) % -% C = GrB.apply (C, M, '|', '~', A) C |= ~A -% C = GrB.apply ('~', A) C = ~A +% C = GrB.mxm (C, M, '+', '+.*', A, B) C += A*B +% C = GrB.mxm (C, M, '+', A, '+.*', B) C += A*B +% C = GrB.mxm ('+', '+,*', C, M, A, B) C += A*B +% +% C = GrB.mxm ('+.*', A, B) C = A*B +% C = GrB.mxm (A, '+.*', B) C = A*B +% C = GrB.mxm (C, M, A, '+.*', B) C = A*B % % c = GrB.reduce (c, '+', 'max', A) c += max (A) % c = GrB.reduce ('max', A) c = max (A) @@ -458,12 +546,13 @@ % c = GrB.reduce (c, 'max', A) c = max (A) % % See also sparse. - -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. properties (SetAccess = private, GetAccess = private) - % The struct contains the entire opaque content of a GraphBLAS GrB_Matrix. + % The struct contains the entire opaque content of a GraphBLAS + % GrB_Matrix. opaque = [ ] ; end @@ -473,7 +562,7 @@ % GrB: GraphBLAS matrix constructor %--------------------------------------------------------------------- - function C = GrB (varargin) + function C = GrB (arg1, arg2, arg3, arg4) %GRB GraphBLAS constructor: create a GraphBLAS sparse matrix. % % C = GrB (A) ; GrB copy of a matrix A, same type and format @@ -485,122 +574,190 @@ % C = GrB (A, type, format) ; GrB copy of A, new type and format % C = GrB (A, format, type) ; ditto % - % C = GrB (m, n, type) ; empty m-by-n GrB type matrix, default format - % C = GrB (m, n, format) ; empty m-by-n GrB double matrix, given format + % C = GrB (m,n, type) ; empty m-by-n GrB type matrix, default format + % C = GrB (m,n, format) ; empty m-by-n GrB double matrix, given format % - % C = GrB (m, n, type, format) ; empty m-by-n matrix, given type & format - % C = GrB (m, n, format, type) ; ditto + % C = GrB (m,n,type,format) ; empty m-by-n matrix, given type & format + % C = GrB (m,n,format,type) ; ditto % % See also sparse. - if (nargin == 1 && ... - (isstruct (varargin {1}) && isfield (varargin {1}, 'GraphBLAS'))) - % C = GrB (A), where the input A is a GraphBLAS struct as - % returned by another GrB* function, but this usage is not meant - % for the end-user. It is only used internally in @GrB. See for - % @GrB/mxm, which uses C = GrB (gbmxm (args)), and the - % typecasting methods, C = double (C), etc. The output of GrB is - % a GraphBLAS object. - C.opaque = varargin {1} ; - else - if (isa (varargin {1}, 'GrB')) - % extract the contents of the GrB object as its opaque struct - % so the gbnew mexFunction can access it. - varargin {1} = varargin {1}.opaque ; + if (nargin == 1) + if (isstruct (arg1)) + % C = GrB (A), where the input A is a GraphBLAS struct as + % returned by another GrB* function, but this usage is not + % meant for the end-user. It is only used internally in + % @GrB, to convert a GraphBLAS struct computed by a + % GraphBLAS mexFunction into a GrB matrix object. + C.opaque = arg1 ; + elseif (isobject (arg1)) + % arg1 is already a GrB matrix; nothing to do + C = arg1 ; + else + % arg1 is a MATLAB matrix; convert to a GrB matrix + C.opaque = gbnew (arg1) ; + end + else + if (isobject (arg1)) + % extract the contents of the GrB object as its opaque + % struct so the gbnew mexFunction can access it. + arg1 = arg1.opaque ; + end + % varargin is more elegant, but it is slower than the switch + switch (nargin) + case 2 + C.opaque = gbnew (arg1, arg2) ; + case 3 + C.opaque = gbnew (arg1, arg2, arg3) ; + case 4 + C.opaque = gbnew (arg1, arg2, arg3, arg4) ; + end end - C.opaque = gbnew (varargin {:}) ; - end end %--------------------------------------------------------------------- % implicitly-defined methods %--------------------------------------------------------------------- - % The following methods work without any implemention needed here: + % The following methods work without any implemention needed here, + % because they are built-in MATLAB m-files that can operate with GrB + % inputs: % - % flipdim fliplr flipud cast isrow iscolumn ndims sprank etreeplot - % spy gplot + % matrix operations: flipdim fliplr flipud cast isrow iscolumn ndims + % sprank etreeplot spy gplot reallog realpow realsqrt % - % bicgstabl bicgstab cgs minres gmres bicg pcg qmr rjr tfqmr lsqr + % iterative solvers: bicgstabl bicgstab cgs minres gmres bicg pcg + % qmr rjr tfqmr lsqr %--------------------------------------------------------------------- % FUTURE:: many these could also be overloaded: %--------------------------------------------------------------------- - % Some of these are trivial (like sin and cos, which would be unary - % operators defined for GrB matrices of type 'double', 'single', or - % 'complex'). Others are not appropriate for sparse matrices (such - % as svd), but the inputs to them could be typecasted to MATLAB full - % matrices ('double', 'single', or 'complex'). Still more have no - % matrix inputs (linspace, ...) and thus cannot be overloaded. + % methods in the MATLAB/ops folder: + % + % colon idivide ismembertol uniquetol + % m-files: intersect ismember setdiff setxorunion unique + % (if 'sort' is overloaded, and 1D indexing added, + % then all these will work for GrB matrices) - % methods 'double' that are not yet implemented here: + % methods in the MATLAB/datatypes folder: % - % accumarray acos acosd acosh acot acotd acoth acsc acscd acsch - % airy asec asecd asech asin asind asinh atan atan2 atan2d atand - % atanh bernoulli besselh besseli besselj besselk bessely betainc - % betaincinv bsxfun charpoly chebyshevT chebyshevU cos cosd cosh - % coshint cosint cot cotd coth csc cscd csch cummax cummin cumprod - % cumsum dawson det diff dilog dirac ei ellipticCE ellipticCK - % ellipticCPi ellipticE ellipticF ellipticK ellipticNome ellipticPi - % erf erfc erfcinv erfcx erfi erfinv euler exp expm1 fresnelc - % fresnels gamma gammainc gammaincinv gammaln gegenbauerC harmonic - % hermiteH hess hypot ichol igamma ilu imag inv issorted - % issortedrows jacobiP jordan kummerU laguerreL legendreP linsolve - % log log10 log1p log2 logint ltitr maxk mink minpoly mod ordeig - % permute pochhammer poly2sym polylog pow2 psi qrupdate rcond - % reallog realpow realsqrt rem sec secd sech signIm sin sind sinh - % sinhint sinint sort sortrowsc ssinint superiorfloat tan tand tanh - % whittakerM whittakerW wrightOmega zeta + % typecast swapbytes + + % methods in the MATLAB/datafun folder: % - % not needed: colon factor divisors delete triangularPulse - % rectangularPulse + % cummax cummin cumprod cumsum diff histcounts islocalmax + % ismissing issorted maxk mink movmad movmax movmean movmedian + % movmin movprod movstd movsum movvar rmmissing rmoutliers + % sort sortrows standardizeMissing topkrows + % + % m-files: bounds corrcoef cov del2 fillmissing filloutliers + % gradient isoutlier issortedrows mean median mode normalize + % rescale smoothdata std var + + % methods the 'double' class that are not yet implemented here: + % + % Possible 'double' functions to overload in the future (note that + % mod and rem are not the same as the ANSI fmod or remainder, but + % the MATLAB rem is almost the same as the ANSI fmod): + % + % mod rem unwrap sind asind cosd acosd tand + % atand secd asecd cscd acscd cotd acotd atan2d + % + % not needed: + % + % special functions: airy bernoulli besselh besseli besselj + % besselk bessely betainc betaincinv chebyshevT chebyshevU + % coshint cosint dawson dilog dirac ei ellipticCE ellipticCK + % ellipticCPi ellipticE ellipticF ellipticK ellipticNome + % ellipticPi erfcinv erfcx erfi erfinv fresnelc fresnels + % gammainc gammaincinv harmonic igamma jacobiP kummerU laguerreL + % legendreP logint pochhammer psi signIm sinhint sinint ssinint + % whittakerM whittakerW wrightOmega zeta triangularPulse + % rectangularPulse + % + % eigenvalue-related: charpoly euler gegenbauerC hermiteH jordan + % minpoly poly2sym polylog + % + % others: colon factor divisors superiorfloat % methods in MATLAB/matfun not implemented here: % - % balance cdf2rdf chol cholupdate condeig condest cond - % decomposition det expm funm gsvd hess inv ldl linsolve logm lscov - % lsqminnorm ltitr lu normest1 normest null ordeig ordqz ordschur - % orth pinv planerot polyeig qrdelete qrinsert qr qrupdate qz rank - % rcond rref rsf2csf schur sqrtm svd sylvester trace vecnorm + % balance cdf2rdf chol cholupdate condeig condest cond + % decomposition det expm funm gsvd hess inv ldl linsolve logm + % lscov lsqminnorm ltitr lu normest1 normest null ordeig ordqz + % ordschur orth pinv planerot polyeig qrdelete qrinsert qr + % qrupdate qz rank rcond rref rsf2csf schur sqrtm svd sylvester + % trace vecnorm % methods in MATLAB/sparfun not implemented here: % - % colperm delsq dissect eigs ichol ilu spalloc spaugment spconvert - % spdiags svds symbfact symmlq unmesh + % colperm delsq dissect eigs ichol ilu spalloc spaugment + % spconvert spdiags svds symbfact symmlq unmesh % - % not needed: treeplot treelayout numgrid nested spparms + % not needed: treeplot treelayout numgrid nested spparms % methods in MATLAB/elmat not implemented here: % - % accumarray blkdiag bsxfun cat circshift compan gallery hadamard - % hankel hilb inf invhilb ipermute isequaln isequalwithequalnans - % nan ndgrid pascal permute repelem rot90 shiftdim toeplitz vander - % wilkinson + % accumarray blkdiag bsxfun cat circshift compan gallery + % hadamard hankel hilb inf invhilb ipermute isequaln nan ndgrid + % pascal permute repelem rot90 shiftdim toeplitz vander + % wilkinson % - % not needed: linspace logspace ind2sub sub2ind meshgrid pi - % freqspace flintmax intmax intmin squeeze realmin realmax i j - % magic rosser + % not needed: linspace logspace ind2sub sub2ind meshgrid pi + % freqspace flintmax intmax intmin squeeze realmin realmax i j + % magic rosser % methods for classes graph and digraph not yet implemented: % - % addedge addnode bfsearch centrality conncomp dfsearch distances - % findedge findnode isisomorphic isomorphism maxflow nearest - % outedges rmedge rmnode shortestpath shortestpathtree simplify - % - % GrB.bfs is like graph/bfsearch and graph/shortestpathtree. + % addedge addnode bfsearch centrality conncomp dfsearch + % distances findedge findnode isisomorphic isomorphism maxflow + % nearest outedges rmedge rmnode shortestpath shortestpathtree + % simplify % methods for class graph (not in digraph class) not yet implemented: % - % bctree biconncomp minspantree neighbors + % bctree biconncomp minspantree neighbors % methods for class digraph (not in graph class) not yet implemented: % - % condensation inedges isdag predecessors successors toposort - % transclosure transreduction + % condensation inedges isdag predecessors successors toposort + % transclosure transreduction - % methods in LAGraph: - % - % betweeness-centrality, etc ... + % methods in LAGraph: (see the LAGraph/Source folder) + + %--------------------------------------------------------------------- + % MATLAB operator overloading + %--------------------------------------------------------------------- + + C = and (A, B) ; % C = (A & B) + C = ctranspose (A) ; % C = A' + i = end (A, k, ndims) ; % for A (1:end,1:end) + C = eq (A, B) ; % C = (A == B) + C = ge (A, B) ; % C = (A >= B) + C = gt (A, B) ; % C = (A > B) + C = horzcat (varargin) ; % C = [A , B] + C = ldivide (A, B) ; % C = A .\ B + C = le (A, B) ; % C = (A <= B) + C = lt (A, B) ; % C = (A < B) + C = minus (A, B) ; % C = A - B + C = mldivide (A, B) ; % C = A \ B + C = mpower (A, B) ; % C = A^B + C = mrdivide (A, B) ; % C = A / B + C = mtimes (A, B) ; % C = A * B + C = ne (A, B) ; % C = (A ~= B) + C = not (G) ; % C = ~A + C = or (A, B) ; % C = (A | B) + C = plus (A, B) ; % C = A + B + C = power (A, B) ; % C = A .^ B + C = rdivide (A, B) ; % C = A ./ B + I = subsindex (A) ; % for C = X (A), using A as index I + C = subsasgn (C, S, A) ; % C (I,J) = A or C (M) = A + C = subsref (A, S) ; % C = A (I,J) or C = A (M) + C = times (A, B) ; % C = A .* B + C = transpose (G) ; % C = A.' + C = uminus (G) ; % C = -A + C = uplus (G) ; % C = +A + C = vertcat (varargin) ; % C = [A ; B] %--------------------------------------------------------------------- % Methods that overload built-in MATLAB functions: @@ -617,40 +774,83 @@ % DiGraph is a MATLAB directed digraph. C = abs (G) ; + C = acos (G) ; + C = acosh (G) ; + C = acot (G) ; + C = acoth (G) ; + C = acsc (G) ; + C = acsch (G) ; C = all (G, option) ; p = amd (G, varargin) ; - C = and (A, B) ; + C = angle (G) ; C = any (G, option) ; - assert (G) ; - [arg1, arg2] = bandwidth (G, uplo) ; + C = asec (G) ; + C = asech (G) ; + C = asin (G) ; + C = asinh (G) ; + assert (G) ; % test assertion + C = atan (G) ; + C = atanh (G) ; + C = atan2 (A, B) ; + + [lo, hi] = bandwidth (G, uplo) ; + C = bitand (A, B, assumedtype) ; + C = bitcmp (A, assumedtype) ; + C = bitget (A, B, assumedtype) ; + C = bitset (A, B, arg3, arg4) ; + C = bitshift (A, B, arg3) ; + C = bitor (A, B, assumedtype) ; + C = bitxor (A, B, assumedtype) ; + +% C = cast (G, ...) built-in works as-is C = ceil (G) ; [p, varargout] = colamd (G, varargin) ; C = complex (A, B) ; C = conj (G) ; - C = diag (G, k) ; + C = cos (G) ; + C = cosh (G) ; + C = cot (G) ; + C = coth (G) ; + C = csc (G) ; + C = csch (G) ; + + C = diag (A, k) ; DiGraph = digraph (G, option) ; + disp (A, level) ; display (G) ; - disp (G, level) ; [p, varargout] = dmperm (G) ; C = double (G) ; - [V, varargout] = eig (G, varargin) ; - i = end (G, k, ndims) ; + + [V, varargout] = eig (G, varargin) ; % uses GrB matrices C = eps (G) ; + C = erf (G) ; + C = erfc (G) ; [parent, varargout] = etree (G, varargin) ; + C = exp (G) ; + C = expm1 (G) ; + C = false (varargin) ; - [I, J, X] = find (G, k, search) ; + [I,J,X] = find (G, k, search) ; C = fix (G) ; C = flip (G, dim) ; C = floor (G) ; c = fprintf (varargin) ; C = full (A, type, identity) ; - Graph = graph (G, varargin) ; + + C = gamma (G) ; + C = gammaln (G) ; + Graph = graph (G, varargin) ; % uses GrB matrices + + C = hypot (A, B) ; + + C = imag (G) ; + C = int8 (G) ; C = int16 (G) ; C = int32 (G) ; C = int64 (G) ; - C = int8 (G) ; - s = isa (G, classname) ; + s = isa (G, type) ; s = isbanded (G, lo, hi) ; +% s = iscolumn (G) built-in works as-is s = isdiag (G) ; s = isempty (G) ; s = isequal (A, B) ; @@ -664,82 +864,75 @@ C = isnan (G) ; s = isnumeric (G) ; s = isreal (G) ; +% s = isrow (G) built-in works as-is s = isscalar (G) ; s = issparse (G) ; s = issymmetric (G, option) ; s = istril (G) ; s = istriu (G) ; s = isvector (G) ; + C = kron (A, B) ; + n = length (G) ; + C = log (G) ; + C = log10 (G) ; + C = log1p (G) ; + [F, E] = log2 (G) ; C = logical (G) ; - [C, I] = max (varargin) ; - C = min (varargin) ; + + C = max (A, B, option) ; + C = min (A, B, option) ; + e = nnz (G) ; X = nonzeros (G) ; - s = norm (G,kind) ; + s = norm (G, kind) ; s = numel (G) ; e = nzmax (G) ; + C = ones (varargin) ; + + C = pow2 (A, B) ; C = prod (G, option) ; + C = real (G) ; C = repmat (G, m, n) ; C = reshape (G, arg1, arg2) ; C = round (G) ; + + C = sec (G) ; + C = sech (G) ; C = sign (G) ; + C = sin (G) ; C = single (G) ; - [arg1, n] = size (G, dim) ; + C = sinh (G) ; + [m, n, t] = size (G, dim) ; C = sparse (G) ; C = spfun (fun, G) ; C = spones (G, type) ; - C = sprand (G) ; - C = sprandn (G) ; - C = sprandsym (G, varargin) ; + C = sprand (arg1, arg2, arg3) ; + C = sprandn (arg1, arg2, arg3) ; + C = sprandsym (arg1, arg2) ; c = sprintf (varargin) ; C = sqrt (G) ; C = sum (G, option) ; [p, varargout] = symamd (G, varargin) ; p = symrcm (G) ; + + C = tan (G) ; + C = tanh (G) ; L = tril (G, k) ; U = triu (G, k) ; C = true (varargin) ; + + C = uint8 (G) ; C = uint16 (G) ; C = uint32 (G) ; C = uint64 (G) ; - C = uint8 (G) ; - C = xor (A, B) ; - C = zeros (varargin) ; - %--------------------------------------------------------------------- - % MATLAB operator overloading - %--------------------------------------------------------------------- + C = xor (A, B) ; - C = ctranspose (A) ; % C = A' - C = eq (A, B) ; % C = (A == B) - C = ge (A, B) ; % C = (A >= B) - C = gt (A, B) ; % C = (A > B) - C = horzcat (varargin) ; % C = [A , B] - C = ldivide (A, B) ; % C = A .\ B - C = le (A, B) ; % C = (A <= B) - C = lt (A, B) ; % C = (A < B) - C = minus (A, B) ; % C = A - B - C = mldivide (A, B) ; % C = A \ B - C = mpower (A, B) ; % C = A^B - C = mrdivide (A, B) ; % C = A / B - C = mtimes (A, B) ; % C = A * B - C = ne (A, B) ; % C = (A ~= B) - C = not (G) ; % C = ~A - C = or (A, B) ; % C = (A | B) - C = plus (A, B) ; % C = A + B - C = power (A, B) ; % C = A .^ B - C = rdivide (A, B) ; % C = A ./ B - C = subsasgn (C, S, A) ; % C (I,J) = A - C = subsref (A, S) ; % C = A (I,J) - C = times (A, B) ; % C = A .* B - C = transpose (G) ; % C = A.' - C = uminus (G) ; % C = -A - C = uplus (G) ; % C = +A - C = vertcat (varargin) ; % C = [A ; B] + C = zeros (varargin) ; end @@ -751,60 +944,71 @@ % All of these are used as GrB.method (...), with the "GrB." prefix. % The input matrices (A, B, C, M, ...) are of any kind (GraphBLAS, - % MATLAB sparse, or MATLAB full). The output matrix C or Cout is a - % GraphBLAS matrix. + % MATLAB sparse, or MATLAB full). The output matrix C is a GraphBLAS + % matrix. - init ; - finalize ; + % Some of the methods listed below are high-level graph algorithms that + % rely on GrB objects internally (bfs, dnn, ktruss, mis, pagerank, and + % tricount), for simplicity and readability. All of the other methods + % extract the opaque content of the GrB objects just once, operate on + % them, and then cast their results back into a MATLAB GrB object just + % once. This makes for less-readable MATLAB code, but it avoids the + % performance cost of accessing/modifying a MATLAB object. + + MATLAB_vs_GrB ; + C = apply (Cin, M, accum, op, A, desc) ; + C = apply2 (Cin, M, accum, op, A, B, desc) ; + C = assign (Cin, M, accum, A, I, J, desc) ; + [v, parent] = bfs (A, s, varargin) ; % uses GrB matrices + binopinfo (op, type) ; + C = build (I, J, X, m, n, dup, type, desc) ; + b = burble (b) ; + c = chunk (c) ; clear ; + [C, I, J] = compact (A, id) ; descriptorinfo (d) ; - unopinfo (op, type) ; - binopinfo (op, type) ; - monoidinfo (monoid, type) ; - selectopinfo (op) ; - semiringinfo (s, type) ; - nthreads = threads (varargin) ; - c = chunk (varargin) ; - b = burble (varargin) ; + Y = dnn (W, bias, Y0) ; % uses GrB matrices + C = eadd (Cin, M, accum, op, A, B, desc) ; C = empty (arg1, arg2) ; - s = type (A) ; - s = issigned (type) ; - s = isfull (A) ; + C = emult (Cin, M, accum, op, A, B, desc) ; + x = entries (A, arg2, arg3) ; + C = expand (scalar, A, type) ; + C = extract (Cin, M, accum, A, I, J, desc) ; + [I, J, X] = extracttuples (A, desc) ; + C = eye (m, n, type) ; + finalize ; f = format (arg) ; + C = incidence (A, varargin) ; + init ; s = isbyrow (A) ; s = isbycol (A) ; - C = expand (scalar, A) ; - C = prune (A, identity) ; - C = offdiag (A) ; - C = eye (varargin) ; - C = speye (varargin) ; - C = random (varargin) ; - C = build (varargin) ; - [I,J,X] = extracttuples (varargin) ; - Cout = mxm (varargin) ; - Cout = select (varargin) ; - Cout = assign (varargin) ; - Cout = subassign (varargin) ; - Cout = vreduce (varargin) ; - Cout = reduce (varargin) ; - Cout = kronecker (varargin) ; - Cout = trans (varargin) ; - Cout = eadd (varargin) ; - Cout = emult (varargin) ; - Cout = apply (varargin) ; - Cout = extract (varargin) ; - [r, stats] = pagerank (A, opts) ; - C = ktruss (A, k, check) ; - s = tricount (A, check) ; + s = isfull (A) ; + s = issigned (arg) ; + C = kronecker (Cin, M, accum, op, A, B, desc) ; + C = ktruss (A, k, check) ; % uses GrB matrices L = laplacian (A, type, check) ; - C = incidence (A, varargin) ; - [v, parent] = bfs (A, s, varargin) ; - iset = mis (A, check) ; - Y = dnn (W, bias, Y0) ; - result = entries (A, varargin) ; + iset = mis (A, check) ; % uses GrB matrices + monoidinfo (monoid, type) ; + C = mxm (Cin, M, accum, semiring, A, B, desc) ; result = nonz (A, varargin) ; - [C, I, J] = compact (A, id) ; s = normdiff (A, B, kind) ; + C = offdiag (A) ; + ctype = optype (a, b) ; + [r, stats] = pagerank (A, opts) ; % uses GrB matrices + C = prune (A, identity) ; + C = random (varargin) ; + C = reduce (cin, accum, monoid, A, desc) ; + C = select (Cin, M, accum, selectop, A, b, desc) ; + selectopinfo (op) ; + semiringinfo (s, type) ; + C = speye (m, n, type) ; + C = subassign (Cin, M, accum, A, I, J, desc) ; + nthreads = threads (nthreads) ; + C = trans (Cin, M, accum, A, desc) ; + s = tricount (A, check, d) ; % uses GrB matrices + s = type (A) ; + unopinfo (op, type) ; + C = vreduce (Cin, M, accum, monoid, A, desc) ; end end diff --git a/GraphBLAS/@GrB/MATLAB_vs_GrB.m b/GraphBLAS/@GrB/MATLAB_vs_GrB.m new file mode 100644 index 0000000000..ba257b8321 --- /dev/null +++ b/GraphBLAS/@GrB/MATLAB_vs_GrB.m @@ -0,0 +1,280 @@ +%% Operations MATLAB matrices vs GraphBLAS matrices +% +% Most of the overloaded operations on GrB matrices work just the same as +% the MATLAB operations of the same name. There are some important +% differences. In future versions, the GrB MATLAB interface to +% GraphBLAS may be modified to reduce these differences. +% +% ------------------------------------------------ +%% Matrix classes and types: +% ------------------------------------------------ +% +% MATLAB supports 3 kinds of sparse matrices: logical, double, and +% double complex. For single precision floating-point (real or +% complex), and integer matrices, MATLAB only supports dense matrices, +% not sparse. +% +% GraphBLAS supports all types: logical, int8, int16, int32, int64, +% uint8, uint16, uint32, uint64, single, double, single complex, and +% double complex. GraphBLAS has only a single class: the GrB object. +% It uses a 'type' to represent these different data types. See help +% GrB.type for more details. +% +% ------------------------------------------------ +%% Explicit zeros: +% ------------------------------------------------ +% +% MATLAB always drops explicit zeros from its sparse matrices. +% GraphBLAS never drops them, except on request (A = GrB.prune (A)). +% This difference will always exist between MATLAB and GraphBLAS. +% +% GraphBLAS cannot drop zeros automatically, since the explicit zero +% might be meaningful. The value zero is the additive identity for +% the single monoid supported by MATLAB (the '+' of the '+.*' +% conventional semiring). MATLAB has only two semirings ('+.*.double' +% and '+.*.double complex'). GraphBLAS supports both of those, but +% many 1000s more, many of which have a different identity value. +% In a shortest-path problem, for example, an edge of weight zero is +% very different than no edge at all (the identity is inf, for the +% 'min' monoid often used in path problems). +% +% ------------------------------------------------ +%% MATLAB linear indexing: +% ------------------------------------------------ +% +% In MATLAB, as in A = rand (3) ; X = A (1:6) extracts the first two +% columns of A as a 6-by-1 vector. This is not yet supported in +% GraphBLAS, but may be added in the future. +% +% ------------------------------------------------ +%% Increasing/decreasing the size of a matrix: +% ------------------------------------------------ +% +% This can be done with a MATLAB matrix, and the result is a sparse +% 10-by-10 sparse matrix A: +% +% clear A +% A (1) = sparse (pi) % A is created as 1-by-1 +% A (10,10) = 42 % A becomes 10-by-10 +% A (5,:) = [ ] % delete row 5 +% +% The GraphBLAS equivalent does not yet work, since submatrix indexing +% does not yet increase the size of the matrix: +% +% clear A +% A (1) = GrB (pi) % fails since A does not exist +% A = GrB (pi) % works +% A (10,10) = 42 % fails, since A is 1-by-1 +% +% This feature is not yet supported but may be added in the future. +% +% ------------------------------------------------ +%% The outputs of min and max, and operations on complex matrices: +% ------------------------------------------------ +% +% MATLAB can compute the min and max on complex values (they return +% the entry with the largest magnitude). This is not well-defined +% mathematically, since the resulting min and max operations cannot be +% used as monoids, as they can for real types (integer or +% floating-point types). As a result, GraphBLAS does not yet support +% min and max for complex types. +% +% The 2nd output for [x,i] = min (...) and max do not work in +% GraphBLAS, and the 'includenan' option is also not available. +% GraphBLAS uses the 'omitnan' behavior, which is the default in +% MATLAB. +% +% Likewise, logical comparisons (< <= > >=) are not well-defined +% mathematically for complex types. MATLAB defines them, but +% GraphBLAS does not. GraphBLAS can only compare for equality (==) +% and inequality (~=) with complex types. +% +% These features may be added to GraphBLAS in the future. +% +% ------------------------------------------------ +%% Singleton expansion: +% ------------------------------------------------ +% +% MATLAB can expand a 'singleton' dimension (of size 1) of one input +% to match the required size of the other input. For example, given +% +% A = rand (4) +% x = [10 100 1000 10000] +% +% these computations both scale the columns of x. The results are the +% same: +% +% A.*x % singleton expansion +% A * diag(x) % standard matrix-vector multiply, which works +% +% GraphBLAS does not yet support singleton expansion: +% +% A = GrB (A) +% A * diag (x) % works +% A.*x % fails +% +% ------------------------------------------------ +%% Typecasting from floating-point types to integer: +% ------------------------------------------------ +% +% In MATLAB, the default is to round to the nearest integer. If the +% fractional part is exactly 0.5: the integer with larger magnitude is +% selected. +% +% In GraphBLAS v3.2.2 and earlier, the convention followed the one in +% the C API, which is to truncate (the same as what happens in C when +% typecasting from double to int, for example). +% +% In GraphBLAS v3.3, the typecasting in the MATLAB interface has been +% changed to match the MATLAB behavior, when explicitly converting +% matrices: +% +% G = 100 * rand (4) +% G = GrB (G, 'int8') +% +% If instead, a double matrix is used as-is directly in an integer +% semiring, the C typecasting rules are used: +% +% % suppose A and B are double: +% A = 5 * rand (4) ; +% B = 5 * rand (4) ; +% +% % uses GraphBLAS typecasting +% C = GrB.mxm (A, '+.*.int8', B) +% +% % uses MATLAB typecasting: +% C = GrB.mxm (GrB (A, 'int8'), '+.*.int8', GrB (B, 'int8')) +% +% ------------------------------------------------ +%% Mixing different integers: +% ------------------------------------------------ +% +% MATLAB refuses to compute int16(1) + int8(1). GraphBLAS can do +% this, using the rules listed by: +% +% help GrB.optype +% +% ------------------------------------------------ +%% Combining 32-bit or lower integers and floating-point: +% ------------------------------------------------ +% +% Both MATLAB and GraphBLAS do the work in floating-point. In MATLAB, +% the result is then cast to the integer type. In GraphBLAS, the GrB +% matrix has the floating-point type. MATLAB can only do this if +% the floating-point operand is a scalar; GraphBLAS can work with any +% matrices of valid sizes. +% +% To use the MATLAB rule in GraphBLAS: after computing the result, +% simply typecast to the desired integer type with +% +% A = cast (5 * rand (4), 'int8') ; +% % C is int8: +% C = A+pi +% A = GrB (A) +% % C is double: +% C = A+pi +% % C is now int8: +% C = GrB (C, 'int8') +% +% ------------------------------------------------ +%% 64-bit integers (int64 and uint64) and double: +% ------------------------------------------------ +% +% In MATLAB, both inputs are converted to 80-bit long double +% (floating-poing) and then the result is typecasted back to the +% integer type. In GraphBLAS the work is done in double, and the +% result is left in the double type. +% +% This can be done in MATLAB only if the double operator is a scalar, +% as in A+pi. With GraphBLAS, A+B can mix arbitrary types, but A+pi +% is computed in double, not long double. +% +% This feature may be added to GraphBLAS in the future, by adding +% new operators that internally do their work in long double. +% +% ------------------------------------------------ +%% MATLAB integer operations saturate: +% ------------------------------------------------ +% +% If a = uint8 (255), and b = uint8 (1), then a+b for MATLAB matrices +% is 255. That is, the results saturate on overflow or underflow, to +% the largest and smallest integer respectively. +% +% This kind of arithmetic is not compatible with integer semirings, +% and thus MATLAB does not support integer matrix computations such as +% C=A*B. +% +% GraphBLAS supports integer semirings, and to do so requires +% integer operations that act in a modulo fashion. As a result if +% a=GrB(255,'uint8') and b=GrB(1,'uint8'), then a+b is zero. +% +% It would be possible to add saturating binary operators to replicate +% the saturating integer behavior in MATLAB, since this is useful for +% operations such as A+B or A.*B for signals and images. This may be +% added in the future, as C = GrB.eadd (A, '+saturate', B) for +% example. +% +% This affects the following operators and functions, and likely more +% as well: +% +% + plus +% - minus +% - uminus (as in C = -A) +% .* times +% ./ ldivide +% .\ rdivide +% .^ power +% +% sum, prod: MATLAB converts to double; GraphBLAS keeps the type +% of the input +% +% It does not affect the following: +% +% + uplus +% * mtimes (GraphBLAS can do this, MATLAB can't) +% < lt +% <= le +% > gt +% >= ge +% == eq +% ~= ne +% bitwise operators (bitor, bitand, ...) +% ~ logical negation +% | or +% & and +% ' ctranspose +% .' transpose +% subsref +% subsasgn +% end +% +% ------------------------------------------------ +%% The rules for concatenation differ. +% ------------------------------------------------ +% +% For C = [A1 A2] and [A1 ; A2], the type of C differs. +% GraphBLAS uses the rules given by 'help GrB.optype' +% +% ------------------------------------------------ +%% Bitwise operators: +% ------------------------------------------------ +% +% GraphBLAS includes all the bitwise operators that MATLAB has. In +% addition, GraphBLAS can use the bitwise operations in semirings; for +% example, if A and B are uint8, then: +% +% C = GrB.mxm (A, 'bitor.bitand', B) ; +% +% computes C = A*B using the 'bitor.bitand.uint8' semiring. Try: +% +% GrB.semiringinfo ('bitor.bitand.uint8') +% +%% For more details, see the GraphBLAS user guide in GraphBLAS/Doc. +% +% See also GrB, sparse. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +help GrB.MATLAB_vs_GrB ; + diff --git a/GraphBLAS/@GrB/abs.m b/GraphBLAS/@GrB/abs.m index f5fccde57a..72e117ef6c 100644 --- a/GraphBLAS/@GrB/abs.m +++ b/GraphBLAS/@GrB/abs.m @@ -1,10 +1,13 @@ function C = abs (G) -%ABS Absolute value of a GraphBLAS matrix. +%ABS absolute value. +% C = abs (G) is the absolute value of each entry of G. +% C is always real, even if C is complex. % -% See also sign. +% See also GrB/sign. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB.apply ('abs', G) ; +G = G.opaque ; +C = GrB (gb_abs (G)) ; diff --git a/GraphBLAS/@GrB/acos.m b/GraphBLAS/@GrB/acos.m new file mode 100644 index 0000000000..b1daa27807 --- /dev/null +++ b/GraphBLAS/@GrB/acos.m @@ -0,0 +1,14 @@ +function C = acos (G) +%ACOS inverse cosine. +% C = acos (G) is the inverse cosine of each entry of G. +% Since acos (0) is nonzero, the result is a full matrix. +% C is complex if any (abs(G) > 1). +% +% See also GrB/cos, GrB/cosh, GrB/acosh. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +C = GrB (gb_trig ('acos', G)) ; + diff --git a/GraphBLAS/@GrB/acosh.m b/GraphBLAS/@GrB/acosh.m new file mode 100644 index 0000000000..90b6710b02 --- /dev/null +++ b/GraphBLAS/@GrB/acosh.m @@ -0,0 +1,14 @@ +function C = acosh (G) +%ACOSH inverse hyperbolic cosine. +% C = acosh (G) is the inverse hyperbolic cosine of each entry G. +% Since acosh (0) is nonzero, the result is a full matrix. +% C is complex if any (G < 1). +% +% See also GrB/cos, GrB/acos, GrB/cosh. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +C = GrB (gb_trig ('acosh', gbfull (G))) ; + diff --git a/GraphBLAS/@GrB/acot.m b/GraphBLAS/@GrB/acot.m new file mode 100644 index 0000000000..0dd564c2df --- /dev/null +++ b/GraphBLAS/@GrB/acot.m @@ -0,0 +1,19 @@ +function C = acot (G) +%ACOT inverse cotangent. +% C = acot (G) is the inverse cotangent of each entry of G. +% Since acot (0) is nonzero, C is a full matrix. +% +% See also GrB/cot, GrB/coth, GrB/acoth. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; + +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gbapply ('atan', gbapply ('minv', gbfull (G, type)))) ; + diff --git a/GraphBLAS/@GrB/acoth.m b/GraphBLAS/@GrB/acoth.m new file mode 100644 index 0000000000..4653640c26 --- /dev/null +++ b/GraphBLAS/@GrB/acoth.m @@ -0,0 +1,19 @@ +function C = acoth (G) +%ACOTH inverse hyperbolic cotangent. +% C = acoth (G) is the inverse hyberbolic cotangent of each entry of G. +% Since acoth (0) is nonozero, C is a full matrix. +% C is complex if G is complex, or if any (abs (G) < 1). +% +% See also GrB/cot, GrB/acot, GrB/coth. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gb_trig ('atanh', gbapply ('minv', gbfull (G, type)))) ; + diff --git a/GraphBLAS/@GrB/acsc.m b/GraphBLAS/@GrB/acsc.m new file mode 100644 index 0000000000..9e2e0cf696 --- /dev/null +++ b/GraphBLAS/@GrB/acsc.m @@ -0,0 +1,19 @@ +function C = acsc (G) +%ACSC inverse cosecant. +% C = acsc (G) is the inverse cosecant of each entry of G. +% Since acsc (0) is nonzero, C is a full matrix. +% +% See also GrB/csc, GrB/csch, GrB/acsch. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; + +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gb_trig ('asin', gbapply ('minv', gbfull (G, type)))) ; + diff --git a/GraphBLAS/@GrB/acsch.m b/GraphBLAS/@GrB/acsch.m new file mode 100644 index 0000000000..f0c5113c35 --- /dev/null +++ b/GraphBLAS/@GrB/acsch.m @@ -0,0 +1,18 @@ +function C = acsch (G) +%ACSCH inverse hyperbolic cosecant. +% C = acsch (G) is the inverse hyberbolic cosecant of each entry G. +% Since acsch (0) is nonzero, C is a full matrix. +% +% See also GrB/csc, GrB/acsc, GrB/csch. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gbapply ('asinh', gbapply ('minv', gbfull (G, type)))) ; + diff --git a/GraphBLAS/@GrB/all.m b/GraphBLAS/@GrB/all.m index e85cbf1d5e..3c4007ff93 100644 --- a/GraphBLAS/@GrB/all.m +++ b/GraphBLAS/@GrB/all.m @@ -1,66 +1,22 @@ function C = all (G, option) %ALL True if all elements of a GraphBLAS matrix are nonzero or true. -% -% C = all (G) is true if all entries G are nonzero or true. If G is a +% C = all (G) is true if all entries in G are nonzero or true. If G is a % matrix, C is a row vector with C(j) = all (G (:,j)). % -% C = all (G, 'all') is a scalar, true if all entries G are nonzero or true. +% C = all (G, 'all') is a scalar, true if all entries G are nonzero or true % C = all (G, 1) is a row vector with C(j) = all (G (:,j)) % C = all (G, 2) is a column vector with C(i) = all (G (i,:)) % -% See also any, nnz, GrB.entries. +% See also GrB/any, GrB/nnz, GrB/prod, GrB.entries. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -[m, n] = size (G) ; -desc = struct ('in0', 'transpose') ; +G = G.opaque ; if (nargin == 1) - - % C = all (G) - if (isvector (G)) - % C = all (G) for a vector G results in a scalar C - if (~GrB.isfull (G)) - C = GrB (false, 'logical') ; - else - C = GrB.reduce ('&.logical', G) ; - end - else - % C = all (G) reduces each column to a scalar, - % giving a 1-by-n row vector. - C = GrB.vreduce ('&.logical', G, desc) ; - % if C(j) is true, but the column is sparse, then assign C(j) = 0. - coldegree = GrB.entries (G, 'col', 'degree') ; - C = GrB.subassign (C, C & (coldegree < m), 0)' ; - end - + C = GrB (gb_prod ('&.logical', 'logical', G)) ; else - - % C = all (G, option) - if (isequal (option, 'all')) - % C = all (G, 'all'), reducing all entries to a scalar - if (~GrB.isfull (G)) - C = GrB (false, 'logical') ; - else - C = GrB.reduce ('&.logical', G) ; - end - elseif (isequal (option, 1)) - % C = all (G, 1) reduces each column to a scalar, - % giving a 1-by-n row vector. - C = GrB.vreduce ('&.logical', G, desc) ; - % if C(j) is true, but the column is sparse, then assign C(j) = 0. - coldegree = GrB.entries (G, 'col', 'degree') ; - C = GrB.subassign (C, C & (coldegree < m), 0)' ; - elseif (isequal (option, 2)) - % C = all (G, 2) reduces each row to a scalar, - % giving an m-by-1 column vector. - C = GrB.vreduce ('&.logical', G) ; - % if C(i) is true, but the row is sparse, then assign C(i) = 0. - rowdegree = GrB.entries (G, 'row', 'degree') ; - C = GrB.subassign (C, C & (rowdegree < n), 0) ; - else - gb_error ('unknown option') ; - end + C = GrB (gb_prod ('&.logical', 'logical', G, option)) ; end diff --git a/GraphBLAS/@GrB/amd.m b/GraphBLAS/@GrB/amd.m index 387faa7973..2f4506057a 100644 --- a/GraphBLAS/@GrB/amd.m +++ b/GraphBLAS/@GrB/amd.m @@ -1,11 +1,11 @@ function p = amd (G, varargin) -%AMD approximate minimum degree ordering of a GraphBLAS matrix. +%AMD approximate minimum degree ordering. % See 'help amd' for details. % -% See also amd, GrB/colamd, GrB/symrcm. +% See also GrB/colamd, GrB/symrcm. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. p = builtin ('amd', logical (G), varargin {:}) ; diff --git a/GraphBLAS/@GrB/and.m b/GraphBLAS/@GrB/and.m index 15f9948562..084ae3c53a 100644 --- a/GraphBLAS/@GrB/and.m +++ b/GraphBLAS/@GrB/and.m @@ -1,43 +1,53 @@ function C = and (A, B) -%& logical AND of GraphBLAS matrices. +%& logical AND. % C = (A & B) is the element-by-element logical AND of A and B. One or % both may be scalars. Otherwise, A and B must have the same size. -% GraphBLAS and MATLAB matrices may be combined. % -% See also GrB/or, GrB/xor. +% See also GrB/or, GrB/xor, GrB/not. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -if (isscalar (A)) - if (isscalar (B)) +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +[am, an] = gbsize (A) ; +[bm, bn] = gbsize (B) ; +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; + +if (a_is_scalar) + if (b_is_scalar) % A and B are scalars - C = GrB.emult (A, '&.logical', B) ; + C = GrB (gbemult (A, '&.logical', B)) ; else % A is a scalar, B is a matrix - if (gb_get_scalar (A) == 0) + if (gb_scalar (A) == 0) % A is false, so C is empty, the same size as B - [m, n] = size (B) ; - C = GrB (m, n, 'logical') ; + C = GrB (gbnew (bm, bn, 'logical')) ; else % A is true, so C is B typecasted to logical - C = GrB (B, 'logical') ; + C = GrB (gbnew (B, 'logical')) ; end end else - if (isscalar (B)) + if (b_is_scalar) % A is a matrix, B is a scalar - if (gb_get_scalar (B) == 0) + if (gb_scalar (B) == 0) % B is false, so C is empty, the same size as A - [m, n] = size (A) ; - C = GrB (m, n, 'logical') ; + C = GrB (gbnew (am, an, 'logical')) ; else % B is true, so C is A typecasted to logical - C = GrB (A, 'logical') ; + C = GrB (gbnew (A, 'logical')) ; end else % both A and B are matrices. C is the set intersection of A and B - C = GrB.emult (A, '&.logical', B) ; + C = GrB (gbemult (A, '&.logical', B)) ; end end diff --git a/GraphBLAS/@GrB/angle.m b/GraphBLAS/@GrB/angle.m new file mode 100644 index 0000000000..4e35643571 --- /dev/null +++ b/GraphBLAS/@GrB/angle.m @@ -0,0 +1,19 @@ +function C = angle (G) +%ANGLE phase angle. +% C = angle (G) is the phase angle of each entry of G. +% +% See also GrB/abs. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +[m, n, type] = gbsize (G) ; + +if (contains (type, 'complex')) + C = GrB (gbapply ('carg', G)) ; +else + % C is all zero + C = GrB (gbnew (m, n, type)) ; +end + diff --git a/GraphBLAS/@GrB/any.m b/GraphBLAS/@GrB/any.m index ef9bb11d2c..be84962c44 100644 --- a/GraphBLAS/@GrB/any.m +++ b/GraphBLAS/@GrB/any.m @@ -1,48 +1,22 @@ function C = any (G, option) -%ANY True if any element of a GraphBLAS matrix is nonzero or true. -% +%ANY true if any element of a matrix is nonzero or true. % C = any (G) is true if any entry in G is nonzero or true. If G is a % matrix, C is a row vector with C(j) = any (G (:,j)). % -% C = any (G, 'all') is a scalar, true if any entry in G is nonzero or true. +% C = any (G, 'all') is a scalar, true if any entry in G is nonzero or true % C = any (G, 1) is a row vector with C(j) = any (G (:,j)) % C = any (G, 2) is a column vector with C(i) = any (G (i,:)) % -% See also all, nnz, GrB/nnz, GrB.entries, GrB.nonz. +% See also GrB/all, GrB/sum, GrB/nnz, GrB.entries, GrB.nonz. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -desc = struct ('in0', 'transpose') ; +G = G.opaque ; if (nargin == 1) - - % C = any (G) - if (isvector (G)) - % C = any (G) for a vector G results in a scalar C - C = GrB.reduce ('|.logical', G) ; - else - % C = any (G) reduces each column to a scalar, - % giving a 1-by-n row vector. - C = GrB.vreduce ('|.logical', G, desc)' ; - end - + C = GrB (gb_sum ('|.logical', G)) ; else - - % C = any (G, option) - if (isequal (option, 'all')) - % C = any (G, 'all'), reducing all entries to a scalar - C = GrB.reduce ('|.logical', G) ; - elseif (isequal (option, 1)) - % C = any (G, 1) reduces each column to a scalar, - % giving a 1-by-n row vector. - C = GrB.vreduce ('|.logical', G, desc)' ; - elseif (isequal (option, 2)) - % C = any (G, 2) reduces each row to a scalar, - % giving an m-by-1 column vector. - C = GrB.vreduce ('|.logical', G) ; - else - gb_error ('unknown option') ; - end + C = GrB (gb_sum ('|.logical', G, option)) ; end diff --git a/GraphBLAS/@GrB/apply.m b/GraphBLAS/@GrB/apply.m index b3c6fe1ef9..7924a79016 100644 --- a/GraphBLAS/@GrB/apply.m +++ b/GraphBLAS/@GrB/apply.m @@ -1,37 +1,64 @@ -function Cout = apply (varargin) +function C = apply (arg1, arg2, arg3, arg4, arg5, arg6) %GRB.APPLY apply a unary operator to a matrix. % -% Usage: -% -% Cout = GrB.apply (op, A, desc) -% Cout = GrB.apply (Cin, accum, op, A, desc) -% Cout = GrB.apply (Cin, M, op, A, desc) -% Cout = GrB.apply (Cin, M, accum, op, A, desc) +% C = GrB.apply (op, A) +% C = GrB.apply (op, A, desc) +% C = GrB.apply (Cin, accum, op, A, desc) +% C = GrB.apply (Cin, M, op, A, desc) +% C = GrB.apply (Cin, M, accum, op, A, desc) % % GrB.apply applies a unary operator to the entries in the input matrix A, % which may be a GraphBLAS or MATLAB matrix (sparse or full). See 'help -% GrB.unopinfo' for a list of available unary operators. Cout is returned -% as a GraphBLAS matrix, by default; see 'help GrB/descriptorinfo' for -% more options. +% GrB.unopinfo' for a list of available unary operators. % % The op and A arguments are required. % % accum: a binary operator to accumulate the results. % -% Cin, and the mask matrix M, and the accum operator are optional. If +% Cin, the mask matrix M, the accum operator, and desc are optional. If % either accum or M is present, then Cin is a required input. If desc.in0 % is 'transpose' then A is transposed before applying the operator, as % C = accum (C, f(A')) where f(...) is the unary operator. % -% See also spfun. +% See also GrB/apply2, GrB/spfun. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (arg1)) + arg1 = arg1.opaque ; +end -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +if (isobject (arg2)) + arg2 = arg2.opaque ; +end + +if (nargin > 2 && isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +if (nargin > 4 && isobject (arg5)) + arg5 = arg5.opaque ; +end + +switch (nargin) + case 2 + [C, k] = gbapply (arg1, arg2) ; + case 3 + [C, k] = gbapply (arg1, arg2, arg3) ; + case 4 + [C, k] = gbapply (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbapply (arg1, arg2, arg3, arg4, arg5) ; + case 6 + [C, k] = gbapply (arg1, arg2, arg3, arg4, arg5, arg6) ; +end -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - Cout = GrB (gbapply (args {:})) ; -else - Cout = gbapply (args {:}) ; +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/apply2.m b/GraphBLAS/@GrB/apply2.m new file mode 100644 index 0000000000..83ae110c3a --- /dev/null +++ b/GraphBLAS/@GrB/apply2.m @@ -0,0 +1,70 @@ +function C = apply2 (arg1, arg2, arg3, arg4, arg5, arg6, arg7) +%GRB.APPLY2 apply a binary operator to a matrix, with scalar binding. +% +% C = GrB.apply2 (op, A, B) +% C = GrB.apply2 (op, A, B, desc) +% C = GrB.apply2 (Cin, accum, op, A, B, desc) +% C = GrB.apply2 (Cin, M, op, A, B, desc) +% C = GrB.apply2 (Cin, M, accum, op, A, B, desc) +% +% GrB.apply2 applies a binary operator op(A,B) to a matrix, with one of the +% inputs being the matrix and the other input is bound to a scalar. See +% 'help GrB.binopinfo'. +% +% The op, A, and B arguments are required. One of A or B must be a scalar. +% If a scalar is sparse with no entries, it is treated as the value zero. +% +% accum: a binary operator to accumulate the results. +% +% Cin, the mask matrix M, the accum operator, and desc are optional. If +% either accum or M is present, then Cin is a required input. If B is the +% scalar and desc.in0 is 'transpose' then A is transposed before applying +% the operator. If A is the scalar and desc.in1 is 'transpose.', then the +% input matrix B is tranposed before applying the operator. +% +% See also GrB/apply, GrB/spfun. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (arg1)) + arg1 = arg1.opaque ; +end + +if (isobject (arg2)) + arg2 = arg2.opaque ; +end + +if (isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +if (nargin > 4 && isobject (arg5)) + arg5 = arg5.opaque ; +end + +if (nargin > 5 && isobject (arg6)) + arg6 = arg6.opaque ; +end + +switch (nargin) + case 3 + [C, k] = gbapply2 (arg1, arg2, arg3) ; + case 4 + [C, k] = gbapply2 (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbapply2 (arg1, arg2, arg3, arg4, arg5) ; + case 6 + [C, k] = gbapply2 (arg1, arg2, arg3, arg4, arg5, arg6) ; + case 7 + [C, k] = gbapply2 (arg1, arg2, arg3, arg4, arg5, arg6, arg7) ; +end + +if (k == 0) + C = GrB (C) ; +end + diff --git a/GraphBLAS/@GrB/asec.m b/GraphBLAS/@GrB/asec.m new file mode 100644 index 0000000000..50fe4a5db1 --- /dev/null +++ b/GraphBLAS/@GrB/asec.m @@ -0,0 +1,19 @@ +function C = asec (G) +%ASEC inverse secant. +% C = asec (G) is the inverse secant of each entry of G. +% Since asec (0) is nonzero, the result is a full matrix. +% C is complex if any (abs(G) < 1). +% +% See also GrB/sec, GrB/sech, GrB/asech. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gb_trig ('acos', gbapply ('minv', gbfull (G, type)))) ; + diff --git a/GraphBLAS/@GrB/asech.m b/GraphBLAS/@GrB/asech.m new file mode 100644 index 0000000000..758ddc595c --- /dev/null +++ b/GraphBLAS/@GrB/asech.m @@ -0,0 +1,19 @@ +function C = asech (G) +%ASECH inverse hyperbolic secant. +% C = asech (G) is the inverse hyperbolic secant of each entry of G. +% Since asech (0) is nonzero, the result is a full matrix. C is complex +% if G is complex, or if any real entries are outside of the range [0,1]. +% +% See also GrB/sec, GrB/asec, GrB/sech. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gb_trig ('acosh', gbapply ('minv', gbfull (G, type)))) ; + diff --git a/GraphBLAS/@GrB/asin.m b/GraphBLAS/@GrB/asin.m new file mode 100644 index 0000000000..fb57904ef7 --- /dev/null +++ b/GraphBLAS/@GrB/asin.m @@ -0,0 +1,13 @@ +function C = asin (G) +%ASIN inverse sine. +% C = asin (G) is the inverse sine of each entry of G. +% C is complex if any entry in any (abs(G) > 1). +% +% See also GrB/sin, GrB/sinh, GrB/asinh. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +C = GrB (gb_trig ('asin', G)) ; + diff --git a/GraphBLAS/@GrB/asinh.m b/GraphBLAS/@GrB/asinh.m new file mode 100644 index 0000000000..25767317d4 --- /dev/null +++ b/GraphBLAS/@GrB/asinh.m @@ -0,0 +1,19 @@ +function C = asinh (G) +%ASINH inverse hyperbolic sine. +% C = asinh (G) is the inverse hyberbolic sine of each entry G. +% +% See also GrB/sin, GrB/asin, GrB/sinh. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; + +if (~gb_isfloat (gbtype (G))) + op = 'asinh.double' ; +else + op = 'asinh' ; +end + +C = GrB (gbapply (op, G)) ; + diff --git a/GraphBLAS/@GrB/assert.m b/GraphBLAS/@GrB/assert.m index 30b7433dc7..6cb6d8eca6 100644 --- a/GraphBLAS/@GrB/assert.m +++ b/GraphBLAS/@GrB/assert.m @@ -1,10 +1,10 @@ function assert (G) -%ASSERT generate an error when a condition is violated +%ASSERT generate an error when a condition is violated. % % See also error. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. builtin ('assert', logical (G)) ; diff --git a/GraphBLAS/@GrB/assign.m b/GraphBLAS/@GrB/assign.m index 6e80e8d5f5..457ccd4a75 100644 --- a/GraphBLAS/@GrB/assign.m +++ b/GraphBLAS/@GrB/assign.m @@ -1,20 +1,14 @@ -function Cout = assign (varargin) +function C = assign (arg1, arg2, arg3, arg4, arg5, arg6, arg7) %GRB.ASSIGN: assign a submatrix into a matrix. % -% GrB.assign is an interface to GrB_Matrix_assign and -% GrB_Matrix_assign_[TYPE], computing the GraphBLAS expression: +% C = GrB.assign (Cin, M, accum, A, I, J, desc) % -% C<#M,replace>(I,J) = accum (C(I,J), A) or accum(C(I,J), A') -% -% where A can be a matrix or a scalar. -% -% Usage: -% -% Cout = GrB.assign (Cin, M, accum, A, I, J, desc) +% C(I,J) = A or accum (C(I,J), A) % % Cin and A are required parameters. All others are optional. % The arguments are parsed according to their type. Arguments -% with different types can appear in any order. +% with different types can appear in any order: +% % Cin, M, A: 2 or 3 GraphBLAS or MATLAB sparse/full matrices. % The first three matrix inputs are Cin, M, and A. % If 2 matrix inputs are present, they are Cin and A. @@ -23,7 +17,7 @@ % with one cell input, I is present and J = { }. % with two cell inputs, I is the first cell input and J % is the second cell input. -% desc: an optional struct. +% desc: an optional struct (must appear as the last argument) % % desc: see 'help GrB.descriptorinfo' for details. % @@ -70,10 +64,10 @@ % M: an optional mask matrix, the same size as C. % % Cin: a required input matrix, containing the initial content of the -% matrix C. Cout is the content of C after the assignment is made. +% matrix C. % % All input matrices may be either GraphBLAS and/or MATLAB matrices, in any -% combination. Cout is returned as a GraphBLAS matrix. +% combination. C is returned as a GraphBLAS matrix. % % Example: % @@ -84,29 +78,65 @@ % % d.in0 = 'transpose' % d.mask = 'complement' -% Cout = GrB.assign (Cin, M, A, d) +% C = GrB.assign (Cin, M, A, d) % C2 = Cin % C2 (~M) = AT (~M) -% C2 - sparse (Cout) +% C2 - sparse (C) % % I = [2 1 5] % J = [3 3 1 2] % B = sprandn (length (I), length (J), 0.5) % Cin = sprand (6, 3, 0.5) -% Cout = GrB.assign (Cin, B, {I}, {J}) +% C = GrB.assign (Cin, B, {I}, {J}) % C2 = Cin % C2 (I,J) = B -% C2 - sparse (Cout) +% C2 - sparse (C) % -% See also GrB.subassign, subsasgn +% See also GrB.subassign, GrB/subsasgn. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (arg1)) + arg1 = arg1.opaque ; +end + +if (isobject (arg2)) + arg2 = arg2.opaque ; +end -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +if (nargin > 2 && isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +if (nargin > 4 && isobject (arg5)) + arg5 = arg5.opaque ; +end + +if (nargin > 5 && isobject (arg6)) + arg6 = arg6.opaque ; +end + +switch (nargin) + case 2 + [C, k] = gbassign (arg1, arg2) ; + case 3 + [C, k] = gbassign (arg1, arg2, arg3) ; + case 4 + [C, k] = gbassign (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbassign (arg1, arg2, arg3, arg4, arg5) ; + case 6 + [C, k] = gbassign (arg1, arg2, arg3, arg4, arg5, arg6) ; + case 7 + [C, k] = gbassign (arg1, arg2, arg3, arg4, arg5, arg6, arg7) ; +end -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - Cout = GrB (gbassign (args {:})) ; -else - Cout = gbassign (args {:}) ; +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/atan.m b/GraphBLAS/@GrB/atan.m new file mode 100644 index 0000000000..fa6d3c4b74 --- /dev/null +++ b/GraphBLAS/@GrB/atan.m @@ -0,0 +1,19 @@ +function C = atan (G) +%ATAN inverse tangent. +% C = atan (G) is the inverse tangent of each entry of G. +% +% See also GrB/tan, GrB/tanh, GrB/atanh, GrB/atan2. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; + +if (~gb_isfloat (gbtype (G))) + op = 'atan.double' ; +else + op = 'atan' ; +end + +C = GrB (gbapply (op, G)) ; + diff --git a/GraphBLAS/@GrB/atan2.m b/GraphBLAS/@GrB/atan2.m new file mode 100644 index 0000000000..1df20d56bc --- /dev/null +++ b/GraphBLAS/@GrB/atan2.m @@ -0,0 +1,55 @@ +function C = atan2 (A, B) +%ATAN2 four quadrant inverse tangent. +% C = atan2 (X,Y) is the 4 quadrant arctangent of the entries in X and Y. +% +% See also GrB/tan, GrB/tanh, GrB/atan, GrB/atanh. + +% FUTURE: atan2(A,B) for two matrices A and B is slower than it could be. +% See comments in gb_union_op. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +atype = gbtype (A) ; +btype = gbtype (B) ; + +if (contains (atype, 'complex') || contains (btype, 'complex')) + error ('inputs must be real') ; +end + +if (~gb_isfloat (atype)) + A = gbnew (A, 'double') ; +end + +if (~gb_isfloat (btype)) + B = gbnew (B, 'double') ; +end + +% atan2(A,B) gives the set union of the pattern of A and B + +if (gb_isscalar (A)) + if (gb_isscalar (B)) + % both A and B are scalars + C = GrB (gbemult ('atan2', A, B)) ; + else + % A is a scalar, B is a matrix + C = GrB (gbapply2 ('atan2', A, B)) ; + end +else + if (gb_isscalar (B)) + % A is a matrix, B is a scalar + C = GrB (gbapply2 ('atan2', A, B)) ; + else + % both A and B are matrices. C is the set union of A and B. + C = GrB (gb_union_op ('atan2', A, B)) ; + end +end + diff --git a/GraphBLAS/@GrB/atanh.m b/GraphBLAS/@GrB/atanh.m new file mode 100644 index 0000000000..13b089810a --- /dev/null +++ b/GraphBLAS/@GrB/atanh.m @@ -0,0 +1,13 @@ +function C = atanh (G) +%ATANH inverse hyperbolic tangent. +% C = atanh (G) is the inverse hyberbolic tangent of each entry G. +% C is complex if G is complex, or if any (abs (G) > 1). +% +% See also GrB/tan, GrB/atan, GrB/tanh, GrB/atan2. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +C = GrB (gb_trig ('atanh', G)) ; + diff --git a/GraphBLAS/@GrB/bandwidth.m b/GraphBLAS/@GrB/bandwidth.m index bc08bac282..24216bbc08 100644 --- a/GraphBLAS/@GrB/bandwidth.m +++ b/GraphBLAS/@GrB/bandwidth.m @@ -1,39 +1,34 @@ function [arg1, arg2] = bandwidth (G, uplo) -%BANDWIDTH Determine the bandwidth of a GraphBLAS matrix. +%BANDWIDTH matrix bandwidth. % [lo, hi] = bandwidth (G) returns the upper and lower bandwidth of G. % lo = bandwidth (G, 'lower') returns just the lower bandwidth. % hi = bandwidth (G, 'upper') returns just the upper bandwidth. % -% See also isbanded, isdiag, istril, istriu. +% See also GrB/isbanded, GrB/isdiag, GrB/istril, GrB/istriu. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. % FUTURE: this will be much faster when implemented in a mexFunction. +% It is currently much slower than the MATLAB bandwidth function. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% compute the bandwidth +G = G.opaque ; +[lo, hi] = gb_bandwidth (G) ; -if (GrB.entries (G) == 0) - % matrix is empty - hi = 0 ; - lo = 0 ; -else - desc.base = 'zero-based' ; - [i, j] = GrB.extracttuples (G, desc) ; - b = j - i ; - hi = max (0, double (max (b))) ; - lo = max (0, -double (min (b))) ; -end +% return the result if (nargin == 1) arg1 = lo ; arg2 = hi ; else if (nargout > 1) - gb_error ('too many output arguments') ; + error ('too many output arguments') ; elseif isequal (uplo, 'lower') arg1 = lo ; elseif isequal (uplo, 'upper') arg1 = hi ; else - gb_error ('unrecognized option') ; + error ('unrecognized option') ; end end diff --git a/GraphBLAS/@GrB/bfs.m b/GraphBLAS/@GrB/bfs.m index d7eaa45a90..98454f892b 100644 --- a/GraphBLAS/@GrB/bfs.m +++ b/GraphBLAS/@GrB/bfs.m @@ -1,11 +1,12 @@ function [v, parent] = bfs (A, s, varargin) -%GRB.BFS breadth-first search of a graph, using its adjacency matrix. v -%= GrB.bfs (A, s) computes the breadth-first search of the directed graph -%represented by the square adjacency matrix A. The breadth-first search -%starts at node s. The output v is a sparse vector of size n-by-1, with -%the level of each node, where v(s)=1, and v(i)=k if the path with the -%fewest edges from from s to i has k-1 edges. If i is not reachable from -%s, then v(i) is implicitly zero and does not appear in the pattern of v. +%GRB.BFS breadth-first search of a graph, using its adjacency matrix. +% v = GrB.bfs (A, s) performs the breadth-first search of the directed +% graph represented by the square adjacency matrix A. The breadth-first +% search starts at node s. The output v is a sparse vector of size +% n-by-1, with the level of each node, where v(s)=1, and v(i)=k if the +% path with the fewest edges from from s to i has k-1 edges. If i is not +% reachable from s, then v(i) is implicitly zero and does not appear in +% the pattern of v. % % [v, parent] = GrB.bfs (A, s) also computes the parent vector, % representing the breadth-first search tree. parent(s)=s denotes the @@ -33,7 +34,7 @@ % format ('by row' or 'by col'). % % A must be square. Only the pattern, spones (A), is considered; the -% values of its entries (the edge weights of the graph) are ignored. +% values of its entries (the edge weights of the graph) are ignored. % % Example: % @@ -57,16 +58,18 @@ % % See also graph/bfsearch, graph/shortestpathtree, treeplot. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -%------------------------------------------------------------------------------- +% NOTE: this is a high-level algorithm that uses GrB objects. + +%------------------------------------------------------------------------- % initializations -%------------------------------------------------------------------------------- +%------------------------------------------------------------------------- [m, n] = size (A) ; if (m ~= n) - gb_error ('A must be square') ; + error ('A must be square') ; end % get the string options @@ -82,7 +85,7 @@ case { 'check' } check = true ; otherwise - gb_error ('unknown option') ; + error ('unknown option') ; end end @@ -94,7 +97,7 @@ % determine the method to use, and convert A if necessary if (isequal (kind, 'undirected')) if (check && ~issymmetric (A)) - gb_error ('A must be symmetric') ; + error ('A must be symmetric') ; end if (GrB.isbycol (A)) % A is stored by column but undirected, so use q*A' instead of q*A @@ -107,22 +110,24 @@ end end -% determine the integer type to use, and initialize v as a full integer vector +% determine the integer type to use int_type = 'int64' ; if (n < intmax ('int32')) int_type = 'int32' ; end + +% initialize v as a full integer vector v = full (GrB (1, n, int_type)) ; -%------------------------------------------------------------------------------- +%------------------------------------------------------------------------- % do the BFS -%------------------------------------------------------------------------------- +%------------------------------------------------------------------------- if (nargout == 1) - %--------------------------------------------------------------------------- + %--------------------------------------------------------------------- % just compute the level of each node - %--------------------------------------------------------------------------- + %--------------------------------------------------------------------- q = GrB (1, n, 'logical') ; % q = sparse (1,n) q = GrB.subassign (q, { s }, true) ; % q (s) = 1 @@ -137,9 +142,9 @@ else - %--------------------------------------------------------------------------- + %--------------------------------------------------------------------- % compute both the level and the parent - %--------------------------------------------------------------------------- + %--------------------------------------------------------------------- parent = full (GrB (1, n, int_type)) ; % parent = zeros (1,n) parent = GrB.subassign (parent, { s }, s) ; % parent (s) = s diff --git a/GraphBLAS/@GrB/binopinfo.m b/GraphBLAS/@GrB/binopinfo.m index a3cace2e59..8ac90d4357 100644 --- a/GraphBLAS/@GrB/binopinfo.m +++ b/GraphBLAS/@GrB/binopinfo.m @@ -1,45 +1,41 @@ -function binopinfo (op, type) +function binopinfo (op, optype) %GRB.BINOPINFO list the details of a GraphBLAS binary operator. % -% Usage -% % GrB.binopinfo % GrB.binopinfo (op) -% GrB.binopinfo (op, type) -% -% For GrB.binopinfo(op), the op must be a string of the form -% 'op.type', where 'op' is listed below. The second usage allows the -% type to be omitted from the first argument, as just 'op'. This is -% valid for all GraphBLAS operations, since the type defaults to the -% type of the input matrices. However, GrB.binopinfo does not have a -% default type and thus one must be provided, either in the op as -% GrB.binopinfo ('+.double'), or in the second argument, GrB.binopinfo -% ('+', 'double'). -% -% The MATLAB interface to GraphBLAS provides for 27 different binary -% operators, each of which may be used with any of the 11 types, for -% a total of 27*11 = 297 valid binary operators. Binary operators -% are defined by a string of the form 'op.type', or just 'op'. In -% the latter case, the type defaults to the type of the matrix inputs -% to the GraphBLAS operation. -% -% The 6 comparator operators come in two flavors. For the is* -% operators, the result has the same type as the inputs, x and y, -% with 1 for true and 0 for false. For example isgt.double (pi, 3.0) -% is the double value 1.0. For the second set of 6 operators (eq, -% ne, gt, lt, ge, le), the result is always logical (true or false). -% In a semiring, the type of the add monoid must exactly match the -% type of the output of the multiply operator, and thus -% 'plus.iseq.double' is valid (counting how many terms are equal). -% The 'plus.eq.double' semiring is valid, but not the same semiring -% since the 'plus' of 'plus.eq.double' has a logical type and is thus -% equivalent to 'or.eq.double'. The 'or.eq' is true if any terms -% are equal and false otherwise (it does not count the number of -% terms that are equal). -% -% The following binary operators are available. Many have equivalent -% synonyms, so that '1st' and 'first' both define the first(x,y) = x -% operator. +% GrB.binopinfo (op, optype) +% +% Binary operators are defined by a string of the form 'op.optype', or +% just 'op', where the optype is inferred from the operands. Valid +% optypes are 'logical', 'int8', 'int16', 'int32', 'int64', 'uint8', +% 'uint16', 'uint32', 'uint64', 'single', 'double', 'single complex', +% 'double complex' (the latter can be written as simply 'complex'). +% +% For GrB.binopinfo (op), the op must be a string of the form 'op.optype', +% where 'op' is listed below. The second usage allows the optype to be +% omitted from the first argument, as just 'op'. This is valid for all +% GraphBLAS operations, since the optype can be determined from the +% operands (see Typecasting, below). However, GrB.binopinfo does not have +% any operands and thus the optype must be provided, either in the op as +% GrB.binopinfo ('+.double'), or in the second argument as +% GrB.binopinfo ('+', 'double'). +% +% The 6 comparator operators come in two flavors. For the is* operators, +% the result has the same type as the inputs, x and y, with 1 for true and +% 0 for false. For example isgt.double (pi, 3.0) is the double value 1.0. +% For the second set of 6 operators (eq, ne, gt, lt, ge, le), the result +% is always logical (true or false). In a semiring, the optype of the add +% monoid must exactly match the type of the output of the multiply +% operator, and thus 'plus.iseq.double' is valid (counting how many terms +% are equal). The 'plus.eq.double' semiring is valid, but not the same +% semiring since the 'plus' of 'plus.eq.double' has a logical type and is +% thus equivalent to 'or.eq.double'. The 'or.eq' is true if any terms +% are equal and false otherwise (it does not count the number of terms +% that are equal). +% +% The following binary operators are available for most types. Many have +% equivalent synonyms, so that '1st' and 'first' both define the +% first(x,y) = x operator. % % operator name(s) f(x,y) | operator names(s) f(x,y) % ---------------- ------ | ----------------- ------ @@ -55,35 +51,60 @@ function binopinfo (op, type) % \ rdiv y/x | < lt x < y % | || or lor x | y | >= ge x >= y % & && and land x & y | <= le x <= y -% xor lxor xor(x,y) | -% pair 1 | any x, or y +% xor lxor xor(x,y) | .^ pow x .^ y +% pair 1 | any pick x or y +% +% Comparators (*lt, *gt, *le, *ge) and min/max are not available for +% complex types. % -% The three logical operators, lor, land, and lxor, also come in 11 -% types. z = lor.double (x,y) tests the condition (x~=0) || (y~=0), +% All of the above operators are defined for logical operands, but many +% are redundant. 'min.logical' is the same as 'and.logical', for example. +% Most of the logical operators have aliases: ('lor', 'or', '|') are the +% same, as are ('lxnor', 'xnor', 'eq', '==') for logical types. +% +% The three logical operators, lor, land, and lxor, can be used with any +% real types. z = lor.double (x,y) tests the condition (x~=0) || (y~=0), % and returns the double value 1.0 if true, or 0.0 if false. % +% The following operators are avaiable for single and double (real); their +% definitions are identical to the ANSI C11 versions of these functions: +% atan2, hypot, fmod, remainder, copysign, ldxep (also called 'pow2'). +% All produce the same type as the input, on output. +% +% z = cmplx(x,y) can be computed for x and y as single and double; z is +% single complex or double complex, respectively. +% +% The following bitwise operators are available for any signed or +% unsigned integer types: bitor, bitand, bitxor, bitxnor, bitget, bitset, +% bitclr, and bitshift. +% +% Typecasting: If the optype is omitted from the string (for example, +% GrB.eadd (A, '+', B) or simply C = A+B), then the optype is inferred +% from the type of A and B. See 'help GrB.optype' for details. +% % Example: % % % valid binary operators -% GrB.binopinfo ('+.double') ; +% GrB.binopinfo ('+.double') ; % also a valid unary operator % GrB.binopinfo ('1st.int32') ; +% GrB.binopinfo ('cmplx.single') ; +% GrB.binopinfo ('pow2.double') ; % also a valid unary operator +% GrB.unopinfo ('pow2.double') ; % % % invalid binary operator (an error; this is a unary op): % GrB.binopinfo ('abs.double') ; % % See also GrB.descriptorinfo, GrB.monoidinfo, GrB.selectopinfo, -% GrB.semiringinfo, GrB.unopinfo. - -% FUTURE: add complex binary operators +% GrB.semiringinfo, GrB.unopinfo, GrB.optype. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. if (nargin == 0) help GrB.binopinfo elseif (nargin == 1) gbbinopinfo (op) ; else - gbbinopinfo (op, type) ; + gbbinopinfo (op, optype) ; end diff --git a/GraphBLAS/@GrB/bitand.m b/GraphBLAS/@GrB/bitand.m new file mode 100644 index 0000000000..06ef5c9813 --- /dev/null +++ b/GraphBLAS/@GrB/bitand.m @@ -0,0 +1,45 @@ +function C = bitand (A, B, assumedtype) +%BITAND bitwise AND. +% C = bitand (A,B) is the bitwise AND of A and B. If A and B are +% matrices, the pattern of C is the set intersection of A and B. If one +% of A or B is a nonzero scalar, the scalar is expanded into a sparse +% matrix with the same pattern as the other matrix, and the result is a +% sparse matrix. +% +% With a third parameter, C = bitand (A,B,assumedtype) provides a data +% type to convert A and B to if they are floating-point types. If A or B +% already have integer types, then they are not modified. Otherwise, A or +% B are converted to assumedtype, which can be 'int8', 'int16', 'int32', +% 'int64', 'uint8', 'uint16', 'uint32' or 'uint64'. The default is +% 'uint64'. +% +% The input matrices must be real, and may be either GraphBLAS and/or +% MATLAB matrices, in any combination. C is returned as a GraphBLAS +% matrix. The type of C is given by GrB.optype (A,B), after any +% conversion to assumedtype, if needed. +% +% Example: +% +% A = GrB (magic (4), 'uint8') +% B = GrB (13 * eye (4), 'uint8') ; +% B (3,4) = 107 +% C = bitand (A, B) +% fprintf ('\nA: ') ; fprintf ('%3x ', A) ; fprintf ('\n') ; +% fprintf ('\nB: ') ; fprintf ('%3x ', B) ; fprintf ('\n') ; +% fprintf ('\nC: ') ; fprintf ('%3x ', C) ; fprintf ('\n') ; +% % in MATLAB: +% C2 = bitand (uint8 (A), uint8 (B)) +% isequal (C2, C) +% +% See also GrB/bitor, GrB/bitxor, GrB/bitcmp, GrB/bitshift, GrB/bitget, +% GrB/bitset, GrB/bitclr. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (nargin < 3) + assumedtype = 'uint64' ; +end + +C = GrB (gb_bitwise ('bitand', A, B, assumedtype)) ; + diff --git a/GraphBLAS/@GrB/bitcmp.m b/GraphBLAS/@GrB/bitcmp.m new file mode 100644 index 0000000000..711c672591 --- /dev/null +++ b/GraphBLAS/@GrB/bitcmp.m @@ -0,0 +1,60 @@ +function C = bitcmp (A, assumedtype) +%BITCMP bitwise complement. +% C = bitcmp (A) is the bitwise complement of A. C is a full matrix. To +% complement all the bits in the entries of a sparse matrix, but not the +% implicit entries not in the pattern of C, use +% C = GrB.apply ('bitcmp', A) instead. +% +% With a second parameter, C = bitcmp (A,assumedtype) provides a data type +% to convert A to if it is a floating-point type. If A already has an +% integer type, then it is not modified. Otherwise, A is converted to +% assumedtype, which can be 'int8', 'int16', 'int32', 'int64', 'uint8', +% 'uint16', 'uint32' or 'uint64'. The default is 'uint64'. +% +% Example: +% +% A = GrB (magic (4), 'uint8') +% C = bitcmp (A) +% fprintf ('\nA: ') ; fprintf ('%3x ', A) ; fprintf ('\n') ; +% fprintf ('\nC: ') ; fprintf ('%3x ', C) ; fprintf ('\n') ; +% % in MATLAB: +% C2 = bitcmp (uint8 (A)) +% isequal (C2, C) +% +% See also GrB/bitor, GrB/bitand, GrB/bitxor, GrB/bitshift, GrB/bitget, +% GrB/bitset, GrB/bitclr. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (nargin < 2) + assumedtype = 'uint64' ; +end + +if (isobject (A)) + A = A.opaque ; +end + +atype = gbtype (A) ; + +if (contains (atype, 'complex')) + error ('inputs must be real') ; +end + +if (isequal (atype, 'logical')) + error ('inputs must not be logical') ; +end + +if (~contains (assumedtype, 'int')) + error ('assumedtype must be an integer type') ; +end + +% C will have the same type as A on input +ctype = atype ; + +if (isequal (atype, 'double') || isequal (atype, 'single')) + A = gbnew (A, assumedtype) ; +end + +C = GrB (gbapply ('bitcmp', gbfull (A)), ctype) ; + diff --git a/GraphBLAS/@GrB/bitget.m b/GraphBLAS/@GrB/bitget.m new file mode 100644 index 0000000000..bf95516a9c --- /dev/null +++ b/GraphBLAS/@GrB/bitget.m @@ -0,0 +1,85 @@ +function C = bitget (A, B, assumedtype) +%BITGET get bit. +% C = bitget (A,B) returns the value of the bit at position B in A, where +% A is an integer array. If B(i,j) is an integer in the range 1 (the +% least significant bit) to the number of bits in the data type of A, then +% C(i,j) is that bit of A(i,j). If B(i,j) is outside this range, C(i,j) +% is zero; note that this behavior is an extension to the built-in MATLAB +% bitget, which results in an error for this case. This modified rule +% allows the inputs A and B to be sparse. If B(i,j) is implicitly zero +% (not in the pattern of B), or if A(i,j) is implicitly zero, then C(i,j) +% is not an entry in the pattern of C. +% +% If A and B are matrices, the pattern of C is the set intersection of A +% and B. If one of A or B is a nonzero scalar, the scalar is expanded +% into a sparse matrix with the same pattern as the other matrix, and the +% result is a sparse matrix. +% +% With a third parameter, C = bitget (A,B,assumedtype) provides a data +% type to convert A to if it has a floating-point type. If A already has +% an integer type, then it is not modified. Otherwise, A is converted to +% assumedtype, which can be 'int8', 'int16', 'int32', 'int64', 'uint8', +% 'uint16', 'uint32' or 'uint64'. The default is 'uint64'. +% +% Example: +% +% A = GrB (magic (4)'*137, 'uint16') +% B = GrB (magic (4)) +% C = bitget (A, B) +% fprintf ('\nA: ') ; fprintf ('%3x ', A) ; fprintf ('\n') ; +% fprintf ('\nB: ') ; fprintf ('%3x ', B) ; fprintf ('\n') ; +% fprintf ('\nC: ') ; fprintf ('%3x ', C) ; fprintf ('\n') ; +% % in MATLAB: +% C2 = bitget (uint16 (A), uint16 (B)) +% isequal (C2, C) +% +% See also GrB/bitor, GrB/bitand, GrB/bitxor, GrB/bitcmp, GrB/bitshift, +% GrB/bitset, GrB/bitclr. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (nargin < 3) + assumedtype = 'uint64' ; +end + +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +atype = gbtype (A) ; +btype = gbtype (B) ; + +if (contains (atype, 'complex') || contains (btype, 'complex')) + error ('inputs must be real') ; +end + +if (isequal (atype, 'logical') || isequal (btype, 'logical')) + error ('inputs must not be logical') ; +end + +if (~contains (assumedtype, 'int')) + error ('assumedtype must be an integer type') ; +end + +% C will have the same type as A on input +ctype = atype ; + +% determine the type of A +if (isequal (atype, 'double') || isequal (atype, 'single')) + A = gbnew (A, assumedtype) ; + atype = assumedtype ; +end + +% ensure B has the right type +if (~isequal (btype, atype)) + B = gbnew (B, atype) ; +end + +% extract the bits from each entry of A +C = GrB (gb_emult (A, ['bitget.' atype], B), ctype) ; + diff --git a/GraphBLAS/@GrB/bitor.m b/GraphBLAS/@GrB/bitor.m new file mode 100644 index 0000000000..ff5d0b72ed --- /dev/null +++ b/GraphBLAS/@GrB/bitor.m @@ -0,0 +1,39 @@ +function C = bitor (A, B, assumedtype) +%BITOR bitwise OR. +% C = bitor (A,B) is the bitwise OR of A and B. If A and B are matrices, +% the pattern of C is the set union of A and B. If one of A or B is a +% nonzero scalar, the scalar is expanded into a dense matrix the size of +% the other matrix, and the result is a dense matrix. +% +% With a third parameter, C = bitor (A,B,assumedtype) provides a data type +% to convert A and B to if they are floating-point types. If A or B +% already have integer types, then they are not modified. Otherwise, A or +% B are converted to assumedtype, which can be 'int8', 'int16', 'int32', +% 'int64', 'uint8', 'uint16', 'uint32' or 'uint64'. The default is +% 'uint64'. +% +% Example: +% +% A = GrB (magic (4), 'uint8') +% B = GrB (13 * eye (4), 'uint8') ; +% B (3,4) = 107 +% C = bitor (A, B) +% fprintf ('\nA: ') ; fprintf ('%3x ', A) ; fprintf ('\n') ; +% fprintf ('\nB: ') ; fprintf ('%3x ', B) ; fprintf ('\n') ; +% fprintf ('\nC: ') ; fprintf ('%3x ', C) ; fprintf ('\n') ; +% % in MATLAB: +% C2 = bitor (uint8 (A), uint8 (B)) +% isequal (C2, C) +% +% See also GrB/bitand, GrB/bitxor, GrB/bitcmp, GrB/bitshift, GrB/bitget, +% GrB/bitset, GrB/bitclr. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (nargin < 3) + assumedtype = 'uint64' ; +end + +C = GrB (gb_bitwise ('bitor', A, B, assumedtype)) ; + diff --git a/GraphBLAS/@GrB/bitset.m b/GraphBLAS/@GrB/bitset.m new file mode 100644 index 0000000000..7c41753345 --- /dev/null +++ b/GraphBLAS/@GrB/bitset.m @@ -0,0 +1,189 @@ +function C = bitset (A, B, arg3, arg4) +%BITSET set bit. +% C = bitset (A,B) sets a bit in A to 1, where the bit position is +% determined by B. A is an integer array. If B(i,j) is an integer in the +% range 1 (the least significant bit) to the number of bits in the data +% type of A, then C(i,j) is equal to the value of A(i,j) after setting the +% bit to 1. If B(i,j) is outside this range, C(i,j) is set to A(i,j), +% unmodified; note that this behavior is an extension of the built-in +% MATLAB bigset, which results in an error for this case. This modified +% rule allows the inputs A and B to be sparse. +% +% If A and B are matrices, the pattern of C is the set union of A +% and B. If one of A or B is a nonzero scalar, the scalar is expanded +% into a sparse matrix with the same pattern as the other matrix, and the +% result is a sparse matrix. +% +% If the last input argument is a string, C = bigset (A,B,assumedtype) +% provides a data type to convert A to if it has a floating-point type. +% If A already has an integer type, then it is not modified. Otherwise, A +% is converted to assumedtype, which can be 'int8', 'int16', 'int32', +% 'int64', 'uint8', 'uint16', 'uint32' or 'uint64'. The default is +% 'uint64'. +% +% C = bitset (A,B,V) sets the bit in A(i,j) at position B(i,j) to 0 if +% V(i,j) is zero, or to 1 if V(i,j) is nonzero. If V is a scalar, it +% is implicitly expanded to V * spones (B). +% +% All four arguments may be used, as C = bitset (A,B,V,assumedtype). +% +% Example: +% +% A = GrB (magic (4), 'uint8') +% B = reshape ([1:8 1:8], 4, 4) +% C = bitset (A, B) +% fprintf ('\nA: ') ; fprintf ('%3x ', A) ; fprintf ('\n') ; +% fprintf ('\nB: ') ; fprintf ('%3x ', B) ; fprintf ('\n') ; +% fprintf ('\nC: ') ; fprintf ('%3x ', C) ; fprintf ('\n') ; +% % in MATLAB: +% C2 = bitset (uint8 (A), B) +% isequal (C2, C) +% +% See also GrB/bitor, GrB/bitand, GrB/bitxor, GrB/bitcmp, GrB/bitshift, +% GrB/bitset, GrB/bitclr. + +% FUTURE: bitset(A,B,V) for two matrices A and B is slower than it could be. +% See comments in gb_union_op. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +[am, an, atype] = gbsize (A) ; +[bm, bn, btype] = gbsize (B) ; + +if (contains (atype, 'complex') || contains (btype, 'complex')) + error ('inputs must be real') ; +end + +if (isequal (atype, 'logical') || isequal (btype, 'logical')) + error ('inputs must not be logical') ; +end + +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; + +% get the optional input arguments +if (nargin == 4) + V = arg3 ; + assumedtype = arg4 ; +elseif (nargin == 3) + if (ischar (arg3)) + V = 1 ; + assumedtype = arg3 ; + else + V = arg3 ; + assumedtype = 'uint64' ; + end +else + V = 1 ; + assumedtype = 'uint64' ; +end + +if (~contains (assumedtype, 'int')) + error ('assumedtype must be an integer type') ; +end + +% C will have the same type as A on input +ctype = atype ; + +% determine the type of A +if (isequal (atype, 'double') || isequal (atype, 'single')) + A = gbnew (A, assumedtype) ; + atype = assumedtype ; +end + +% ensure B has the same type as A +if (~isequal (btype, atype)) + B = gbnew (B, atype) ; +end + +% get the matrix or scalar V +if (isobject (V)) + V = V.opaque ; +end +[m, n] = gbsize (V) ; +V_is_scalar = (m == 1) && (n == 1) ; + +if (V_is_scalar) + + % V is a scalar: all bits in A indexed by B are either cleared or set. + if (gb_scalar (V) == 0) + % any bit reference by B(i,j) is set to 0 in A + op = ['bitclr.' atype] ; + else + % any bit reference by B(i,j) is set to 1 in A + op = ['bitset.' atype] ; + end + + if (a_is_scalar) + % A is a scalar + if (b_is_scalar) + % both A and B are scalars + C = gb_union_op (op, A, B) ; + else + % A is a scalar, B is a matrix + C = gbapply2 (op, A, B) ; + end + else + % A is a matrix + if (b_is_scalar) + % A is a matrix, B is scalar + C = gbapply2 (op, A, B) ; + else + % both A and B are matrices + C = gb_union_op (op, A, B) ; + end + end + +else + + % V is a matrix: A and B can be scalars or matrices, but if they + % are matrices, they must have the same size as V. + + % if B(i,j) is nonzero and V(i,j)=1, then: + % C(i,j) = bitset (A (i,j), B (i,j)). + + % if B(i,j) is nonzero and V(i,j)=0 (implicit or explicit), then: + % C(i,j) = bitclr (A (i,j), B (i,j)). + + if (a_is_scalar) + % expand A to a full matrix the same size as V. + A = gb_scalar_to_full (m, n, atype, A) ; + end + if (b_is_scalar) + % expand B to a full matrix the same size as V. + B = gb_scalar_to_full (m, n, atype, B) ; + end + + % Set all bits referenced by B(i,j) to 1, even those that need to be + % set to 0, without considering V(i,j). + C = gb_union_op (['bitset.', atype], A, B) ; + + % The pattern of C is now the set intersection of A and B, but + % bits referenced by B(i,j) have been set to 1, not 0. Construct B0 + % as the bits in B(i,j) that must be set to 0; B0<~V>=B defines the + % pattern of bit positions B0 to set to 0 in A. + d.mask = 'complement' ; + B0 = gbassign (gbnew (m, n, atype), V, B, d) ; + + % Clear the bits in C, referenced by B0(i,j), where V(i,j) is zero. + C = gbeadd (['bitclr.', atype], C, B0) ; + +end + +% return result +if (isequal (gbtype (C), ctype)) + C = GrB (C) ; +else + C = GrB (gbnew (C, ctype)) ; +end + + diff --git a/GraphBLAS/@GrB/bitshift.m b/GraphBLAS/@GrB/bitshift.m new file mode 100644 index 0000000000..a7cc690f3c --- /dev/null +++ b/GraphBLAS/@GrB/bitshift.m @@ -0,0 +1,36 @@ +function C = bitshift (A, B, assumedtype) +%BITSHIFT bitwise left and right shift. +% C = bitshift (A,B) is the bitwise shift of A; if B > 0 then A is shifted +% left by B bits, and if B < 0 then A is shifted right by -B bits. If +% either A or B are scalars, they are expanded to the pattern of the other +% matrix. C has the pattern of A (after expansion, if needed). +% +% With a third parameter, C = bitshift (A,B,assumedtype) provides a data +% type to convert A to if it is a floating-point type. If A already has +% an integer type, then it is not modified. Otherwise, A is converted to +% assumedtype, which can be 'int8', 'int16', 'int32', 'int64', 'uint8', +% 'uint16', 'uint32' or 'uint64'. The default is 'uint64'. +% +% Example: +% +% A = uint8 (magic (4)) +% G = GrB (magic (4), 'uint8') ; +% C1 = bitshift (A, -2) ; +% C2 = bitshift (G, -2) +% isequal (C2, C) +% +% See also GrB/bitor, GrB/bitand, GrB/bitxor, GrB/bitcmp, GrB/bitget, +% GrB/bitset, GrB/bitclr. + +% FUTURE: bitshift(A,B) for two matrices A and B is slower than it could be. +% See comments in gb_union_op. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (nargin < 3) + assumedtype = 'uint64' ; +end + +C = GrB (gb_bitwise ('bitshift', A, B, assumedtype)) ; + diff --git a/GraphBLAS/@GrB/bitxor.m b/GraphBLAS/@GrB/bitxor.m new file mode 100644 index 0000000000..c71345a388 --- /dev/null +++ b/GraphBLAS/@GrB/bitxor.m @@ -0,0 +1,39 @@ +function C = bitxor (A, B, assumedtype) +%BITXOR bitwise XOR. +% C = bitxor (A,B) is the bitwise XOR of A and B. If A and B are +% matrices, the pattern of C is the set union of A and B. If one of A or +% B is a nonzero scalar, the scalar is expanded into a dense matrix the +% size of the other matrix, and the result is a dense matrix. +% +% With a third parameter, C = bitxor (A,B,assumedtype) provides a data +% type to convert A and B to if they are floating-point types. If A or B +% already have integer types, then they are not modified. Otherwise, A or +% B are converted to assumedtype, which can be 'int8', 'int16', 'int32', +% 'int64', 'uint8', 'uint16', 'uint32' or 'uint64'. The default is +% 'uint64'. +% +% Example: +% +% A = GrB (magic (4), 'uint8') +% B = GrB (13 * eye (4), 'uint8') ; +% B (3,4) = 107 +% C = bitxor (A, B) +% fprintf ('\nA: ') ; fprintf ('%3x ', A) ; fprintf ('\n') ; +% fprintf ('\nB: ') ; fprintf ('%3x ', B) ; fprintf ('\n') ; +% fprintf ('\nC: ') ; fprintf ('%3x ', C) ; fprintf ('\n') ; +% % in MATLAB: +% C2 = bitxor (uint8 (A), uint8 (B)) +% isequal (C2, C) +% +% See also GrB/bitor, GrB/bitand, GrB/bitcmp, GrB/bitshift, GrB/bitget, +% GrB/bitset, GrB/bitclr. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (nargin < 3) + assumedtype = 'uint64' ; +end + +C = GrB (gb_bitwise ('bitxor', A, B, assumedtype)) ; + diff --git a/GraphBLAS/@GrB/build.m b/GraphBLAS/@GrB/build.m index 90d7efafcf..0ebf88220f 100644 --- a/GraphBLAS/@GrB/build.m +++ b/GraphBLAS/@GrB/build.m @@ -1,7 +1,5 @@ function C = build (varargin) -%GRB.BUILD construct a GraphBLAS sparse matrix from a list of entries. -% -% Usage +%GRB.BUILD construct a sparse matrix from a list of entries. % % C = GrB.build (I, J, X, m, n, dup, type, desc) % @@ -35,9 +33,8 @@ % % type is a string that defines the type of C (see 'help GrB' for a list % of types). The type need not be the same type as the dup operator -% (unless one has a type of 'complex', in which case both must be -% 'complex'). If the type is not specified, it defaults to the type of -% X. +% (unless one has a complex type, in which case both must have a complex +% type). If the type is not specified, it defaults to the type of X. % % The integer arrays I and J may be double, int64, or uint64: % If I, J, and X are double, the following examples construct the same @@ -48,10 +45,10 @@ % S = double (GrB.build (I, J, X)) ; % S = double (GrB.build (uint64(I), uint64(J), X)) ; % -% I and J need not be in any particular order, but GrB.build is fastest if I -% and J are provided in column-major order if building a MATLAB sparse -% matrix. If desc.format is 'by row', then GrB.build is fastest if I and -% J are in row-major order. +% The row and column indices I and J need not be in any particular order, +% but GrB.build is fastest if I and J are provided in column-major order +% if building a MATLAB sparse matrix. If desc.format is 'by row', then +% GrB.build is fastest if I and J are in row-major order. % % If desc.base is 'zero-based', then I and J are treated as zero-based, % where (0,0) is the first entry in the top left of S, and (m-1,n-1) @@ -63,15 +60,13 @@ % length e, the scalars are expanded into vectors of length e. Any % vectors I, J, and X must all be the same size, e. % -% See also sparse, find, GrB.extracttuples. +% See also sparse, GrB/sparse, GrB/find, GrB.extracttuples. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - C = GrB (gbbuild (args {:})) ; -else - C = gbbuild (args {:}) ; +[C, k] = gbbuild (varargin {:}) ; +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/burble.m b/GraphBLAS/@GrB/burble.m index 66997c2163..9d194119e2 100644 --- a/GraphBLAS/@GrB/burble.m +++ b/GraphBLAS/@GrB/burble.m @@ -1,21 +1,22 @@ -function b = burble (varargin) -%GRB.BURBLE get/set the burble +function b = burble (b) +%GRB.BURBLE get/set the GraphBLAS burble option. % -% Usage: % b = GrB.burble ; % get the current burble % GrB.burble (b) ; % set the burble % % GrB.burble gets and/or sets the burble setting, which controls diagnostic % output in GraphBLAS. To enable this parameter, the SuiteSparse:GraphBLAS -% library must also be compiled with burble enabled (use -DGB_BURBLE=1). The -% default is false. This setting is meant for diagnostic use only, during -% development of GraphBLAS itself. It may also be useful for algorithmic -% development, and is thus documented here. See also spparms ('spumoni', ...). +% library must also be compiled with burble enabled (use -DGB_BURBLE=1). +% The default burble is false. % % See also spparms. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -b = gbburble (varargin {:}) ; +if (nargin == 0) + b = gbburble ; +else + b = gbburble (b) ; +end diff --git a/GraphBLAS/@GrB/ceil.m b/GraphBLAS/@GrB/ceil.m index 0708d6fe31..39f743a2fa 100644 --- a/GraphBLAS/@GrB/ceil.m +++ b/GraphBLAS/@GrB/ceil.m @@ -1,17 +1,15 @@ function C = ceil (G) -%CEIL round entries of a GraphBLAS matrix to nearest integers towards inf. -% See also floor, round, fix. +%CEIL round entries of a matrix to nearest integers towards infinity. +% +% See also GrB/floor, GrB/round, GrB/fix. -% FUTURE: this will be much faster as a mexFunction. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +Q = G.opaque ; -if (isfloat (G) && GrB.entries (G) > 0) - [m, n] = size (G) ; - desc.base = 'zero-based' ; - [i, j, x] = GrB.extracttuples (G, desc) ; - C = GrB.build (i, j, ceil (x), m, n, desc) ; +if (gb_isfloat (gbtype (Q)) && gbnvals (Q) > 0) + C = GrB (gbapply ('ceil', Q)) ; else C = G ; end diff --git a/GraphBLAS/@GrB/chunk.m b/GraphBLAS/@GrB/chunk.m index 3a965afd52..5bc57a2e41 100644 --- a/GraphBLAS/@GrB/chunk.m +++ b/GraphBLAS/@GrB/chunk.m @@ -1,25 +1,28 @@ -function c = chunk (varargin) +function c = chunk (c) %GRB.CHUNK get/set the chunk size to use in GraphBLAS. % -% Usage: % c = GrB.chunk ; % get the current chunk c % GrB.chunk (c) ; % set the chunk c % -% GrB.chunk gets and/or sets the chunk size to use in GraphBLAS, which controls -% how many threads GraphBLAS uses for small problems. The default is 4096. If -% w is a measure of the work required (w = GrB.entries(A) + GrB.entries(B) for -% C=A+B, for example), then the number of threads GraphBLAS uses is min (max -% (1, floor (w/c)), GrB.nthreads). +% GrB.chunk gets and/or sets the chunk size to use in GraphBLAS, which +% controls how many threads GraphBLAS uses for small problems. The +% default is 4096. If w is a measure of the work required (for C=A+B, the +% work is w = GrB.entries(A) + GrB.entries(B), for example) then the number +% of threads GraphBLAS uses is min (max (1, floor (w/c)), GrB.nthreads). % -% Changing the chunk via GrB.chunk(c) causes all subsequent GraphBLAS operations -% to use that chunk size c. The setting persists for the current MATLAB -% session, or until 'clear all' or GrB.clear is used, at which point the setting -% reverts to the default. +% Changing the chunk via GrB.chunk(c) causes all subsequent GraphBLAS +% operations to use that chunk size c. The setting persists for the +% current MATLAB session, or until 'clear all' or GrB.clear is used, at +% which point the setting reverts to the default. % % See also GrB.threads. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -c = gbchunk (varargin {:}) ; +if (nargin == 0) + c = gbchunk ; +else + c = gbchunk (c) ; +end diff --git a/GraphBLAS/@GrB/clear.m b/GraphBLAS/@GrB/clear.m index dea1935ed5..aba7403d99 100644 --- a/GraphBLAS/@GrB/clear.m +++ b/GraphBLAS/@GrB/clear.m @@ -1,19 +1,13 @@ function clear %GRB.CLEAR restore default settings for SuiteSparse:GraphBLAS. -% -% Usage: -% -% GrB.clear -% % GrB.clear clears any non-default setting of the GraphBLAS global -% variables, including GrB.threads, GrB.chunk, and GrB.format, -% and sets them to their defaults. It has no effect on any GrB -% objects. +% variables, including GrB.threads, GrB.chunk, and GrB.format, and sets +% them to their defaults. It has no effect on any GrB objects. % -% See also: clear, GrB.init, GrB.finalize +% See also clear, GrB.init, GrB.finalize. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. gbsetup ; diff --git a/GraphBLAS/@GrB/colamd.m b/GraphBLAS/@GrB/colamd.m index 9f1a1a5962..93ee7e9a78 100644 --- a/GraphBLAS/@GrB/colamd.m +++ b/GraphBLAS/@GrB/colamd.m @@ -1,11 +1,11 @@ function [p, varargout] = colamd (G, varargin) -%COLAMD column approximate minimum degree ordering of a GraphBLAS matrix. +%COLAMD column approximate minimum degree ordering. % See 'help colamd' for details. % -% See also amd. +% See also GrB/amd. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. [p, varargout{1:nargout-1}] = colamd (double (G), varargin {:}) ; diff --git a/GraphBLAS/@GrB/compact.m b/GraphBLAS/@GrB/compact.m index a4e546ee91..f4411a5d24 100644 --- a/GraphBLAS/@GrB/compact.m +++ b/GraphBLAS/@GrB/compact.m @@ -4,13 +4,14 @@ % It has no effect on a MATLAB full matrix, except to convert it to a % GraphBLAS matrix, since all entries are present in a MATLAB full matrix. % -% To remove rows and columns with no entries or only explicit zero entries, -% use C = GrB.compact (A,0). For a MATLAB sparse matrix, GrB.compact (A,0) -% and GrB.compact (A) are identical. +% Explicit zeros in A are treated as entries, and are not removed by +% default. To remove rows and columns with no entries or only explicit +% zero entries, use C = GrB.compact (A,0). For a MATLAB sparse matrix, +% GrB.compact (A,0) and GrB.compact (A) are identical. % -% To remove rows and colums with no entries, or with only entries equal to -% a particular scalar value, use C = GrB.compact (A, id), where id is the -% scalar value. +% To remove rows and colums that either have no entries, or that only have +% entries equal to a particular scalar value, use C = GrB.compact (A, id), +% where id is the scalar value. % % With two additional output arguments, [C,I,J] = GrB.compact (A, ...), % the indices of non-empty rows and columns of A are returned, so that @@ -25,25 +26,37 @@ % A = magic (4) ; % H (I,J) = A % [C, I, J] = GrB.compact (H) -% assert (isequal (C, A)) ; % C and A are the same +% isequal (C, A) % C and A are the same +% isequal (C, H(I,J)) % C and H(I,J) are the same % H (I, J(1)) = 0 % [C, I, J] = GrB.compact (H, 0) -% norm (C - A (:,2:end), 1) +% norm (C - A (:,2:end), 1) == 0 % % See also GrB.entries, GrB.nonz, GrB.prune. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end if (nargin > 1) + % prune identity values from A id = gb_get_scalar (id) ; - if (~(id == 0 && builtin ('issparse', A))) - A = GrB.prune (A, id) ; + if (id ~= 0) + % prune a nonzero identity value from A + A = gbselect (A, '~=', id) ; + elseif (~builtin ('issparse', A)) + % prune zeros from A, but skip this if A is a MATLAB sparse matrix + A = gbselect (A, 'nonzero') ; end end -S = GrB.apply ('1.double', A) ; -I = find (GrB.vreduce ('+', S)) ; -J = find (GrB.vreduce ('+', S, struct ('in0', 'transpose'))) ; -C = GrB.extract (A, { I }, { J }) ; +% get the list of non-empty rows and columns +I = gb_entries (A, 'row', 'list') ; +J = gb_entries (A, 'col', 'list') ; + +% C = A (I,J) +C = GrB (gbextract (A, { I }, { J })) ; diff --git a/GraphBLAS/@GrB/complex.m b/GraphBLAS/@GrB/complex.m index 0673ff531a..7fc2311ca4 100644 --- a/GraphBLAS/@GrB/complex.m +++ b/GraphBLAS/@GrB/complex.m @@ -1,18 +1,102 @@ -function C = complex (A, B) %#ok -%COMPLEX cast a GraphBLAS matrix to MATLAB sparse double complex matrix. -% C = complex (G) will typecast the GraphBLAS matrix G to into a MATLAB -% sparse complex matrix (complex types are not yet supported, however). +function C = complex (A, B) +%COMPLEX cast to a MATLAB sparse double complex matrix. +% C = complex (G) typecasts the GraphBLAS matrix G to into a MATLAB sparse +% complex matrix. % -% To typecast the matrix G to a GraphBLAS sparse complex matrix instead, -% use C = GrB (G, 'complex'). +% With two inputs, C = complex (A,B) returns a MATLAB matrix C = A + 1i*B, +% where A or B are real matrices (MATLAB and/or GraphBLAS, in any +% combination). If A or B are nonzero scalars and the other input is a +% matrix, or if both A and B are scalars, C is full. Otherwise, C is +% sparse. % -% See also cast, GrB, double, single, logical, int8, int16, int32, int64, -% uint8, uint16, uint32, and uint64. +% To typecast the matrix G to a GraphBLAS sparse double complex matrix +% instead, use C = GrB (G, 'complex') or C = GrB (G, 'double complex'). +% To typecast the matrix G to a GraphBLAS single complex matrix, use +% C = GrB (G, 'single complex'). +% +% To construct a complex GraphBLAS matrix from real GraphBLAS matrices +% A and B, use C = A + 1i*B instead. +% +% Since MATLAB does not support sparse single complex matrices, C is +% always returned as a double complex matrix (sparse or full). +% +% See also cast, GrB, GrB/double, GrB/single, GrB/logical, GrB/int8, +% GrB/int16, GrB/int32, GrB/int64, GrB/uint8, GrB/uint16, GrB/uint32, +% GrB/uint64. + +% FUTURE: complex(A,B) for two matrices A and B is slower than it could be. +% See comments in gb_union_op. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (nargin == 1) + + % with a single input, A must be a GraphBLAS matrix (otherwise, + % this overloaded method for GrB objects would not be called). + % Convert A to a double complex matrix C. + A = A.opaque ; + C = gbsparse (A, 'double complex') ; + +else + + if (isobject (A)) + A = A.opaque ; + end + + if (isobject (B)) + B = B.opaque ; + end + + [am, an, atype] = gbsize (A) ; + [bm, bn, btype] = gbsize (B) ; + a_is_scalar = (am == 1) && (an == 1) ; + b_is_scalar = (bm == 1) && (bn == 1) ; -% FUTURE: add complex type(s) + if (contains (atype, 'complex') || contains (btype, 'complex')) + error ('inputs must be real') ; + end -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. + if (a_is_scalar) + if (b_is_scalar) + % both A and B are scalars. C is also a scalar. + A = gbfull (A, 'double') ; + B = gbfull (B, 'double') ; + desc.kind = 'full' ; + C = gbemult ('cmplx.double', A, B, desc) ; + else + % A is a scalar, B is a matrix. C is full, unless A == 0. + if (gb_scalar (A) == 0) + % C = 1i*B, so A = zero, C is sparse. + desc.kind = 'sparse' ; + C = gbapply2 ('cmplx.double', 0, B, desc) ; + else + % expand A and B to full double matrices; C is full + A = gb_scalar_to_full (bm, bn, 'double', A) ; + B = gbfull (B, 'double') ; + desc.kind = 'full' ; + C = gbemult ('cmplx.double', A, B, desc) ; + end + end + else + if (b_is_scalar) + % A is a matrix, B is a scalar. C is full, unless B == 0. + if (gb_scalar (B) == 0) + % C = complex (A); C is sparse + C = gbsparse (A, 'double.complex') ; + else + % expand A and B to full double matrices; C is full + A = gbfull (A, 'double') ; + B = gb_scalar_to_full (am, an, 'double', B) ; + desc.kind = 'full' ; + C = gbemult ('cmplx.double', A, B, desc) ; + end + else + % both A and B are matrices. C is sparse. + desc.kind = 'sparse' ; + C = gbeadd (A, '+', gbapply2 (1i, '*', B), desc) ; + end + end -error ('GrB:unsupported', 'complex type not supported') ; +end diff --git a/GraphBLAS/@GrB/conj.m b/GraphBLAS/@GrB/conj.m index 99f6b65ad2..b6ea69209a 100644 --- a/GraphBLAS/@GrB/conj.m +++ b/GraphBLAS/@GrB/conj.m @@ -1,12 +1,17 @@ function C = conj (G) -%CONJ complex conjugate of a GraphBLAS matrix. -% Since all GraphBLAS matrices are currently real, conj (G) is just G. -% Complex support will be added in the future. +%CONJ complex conjugate. +% C = conj (G) is the complex conjugate of each entry of G. % -% See also real, imag. +% See also GrB/real, GrB/imag. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = G ; +Q = G.opaque ; + +if (contains (gbtype (Q), 'complex')) + C = GrB (gbapply ('conj', Q)) ; +else + C = G ; +end diff --git a/GraphBLAS/@GrB/cos.m b/GraphBLAS/@GrB/cos.m new file mode 100644 index 0000000000..6e76bf7435 --- /dev/null +++ b/GraphBLAS/@GrB/cos.m @@ -0,0 +1,18 @@ +function C = cos (G) +%COS cosine. +% C = cos (G) is the cosine of each entry of G. +% Since cos (0) = 1, the result is a full matrix. +% +% See also GrB/acos, GrB/cosh, GrB/acosh. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gbapply ('cos', gbfull (G, type))) ; + diff --git a/GraphBLAS/@GrB/cosh.m b/GraphBLAS/@GrB/cosh.m new file mode 100644 index 0000000000..631d653ee9 --- /dev/null +++ b/GraphBLAS/@GrB/cosh.m @@ -0,0 +1,18 @@ +function C = cosh (G) +%COSH hyperbolic cosine. +% C = cosh (G) is the hyperbolic cosine of each entry of G. +% Since cosh (0) = 1, the result is a full matrix. +% +% See also GrB/cos, GrB/acos, GrB/acosh. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gbapply ('cosh', gbfull (G, type))) ; + diff --git a/GraphBLAS/@GrB/cot.m b/GraphBLAS/@GrB/cot.m new file mode 100644 index 0000000000..00d0224fd1 --- /dev/null +++ b/GraphBLAS/@GrB/cot.m @@ -0,0 +1,19 @@ +function C = cot (G) +%COT cotangent. +% C = cot (G) is the cotangent of each entry of G. +% Since cot (0) is nonzero, C is a full matrix. +% +% See also GrB/coth, GrB/acot, GrB/acoth. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +if (~gb_isfloat (gbtype (G))) + op = 'tan.double' ; +else + op = 'tan' ; +end + +C = GrB (gbapply ('minv', gbfull (gbapply (op, G)))) ; + diff --git a/GraphBLAS/@GrB/coth.m b/GraphBLAS/@GrB/coth.m new file mode 100644 index 0000000000..2d519b4041 --- /dev/null +++ b/GraphBLAS/@GrB/coth.m @@ -0,0 +1,19 @@ +function C = coth (G) +%COTH hyperbolic cotangent. +% C = coth (G) is the hyperbolic cotangent of each entry of G. +% Since coth (0) is nonzero, C is a full matrix. +% +% See also GrB/cot, GrB/acot, GrB/acoth. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +if (~gb_isfloat (gbtype (G))) + op = 'tanh.double' ; +else + op = 'tanh' ; +end + +C = GrB (gbapply ('minv', gbfull (gbapply (op, G)))) ; + diff --git a/GraphBLAS/@GrB/csc.m b/GraphBLAS/@GrB/csc.m new file mode 100644 index 0000000000..d705c56e88 --- /dev/null +++ b/GraphBLAS/@GrB/csc.m @@ -0,0 +1,19 @@ +function C = csc (G) +%CSC cosecant. +% C = csc (G) is the cosecant of each entry of G. +% Since csc (0) is nonzero, C is a full matrix. +% +% See also GrB/acsc, GrB/csch, GrB/acsch. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +if (~gb_isfloat (gbtype (G))) + op = 'sin.double' ; +else + op = 'sin' ; +end + +C = GrB (gbapply ('minv', gbfull (gbapply (op, G)))) ; + diff --git a/GraphBLAS/@GrB/csch.m b/GraphBLAS/@GrB/csch.m new file mode 100644 index 0000000000..87039e27d4 --- /dev/null +++ b/GraphBLAS/@GrB/csch.m @@ -0,0 +1,19 @@ +function C = csch (G) +%CSCH hyperbolic cosecant. +% C = csch (G) is the hyperbolic cosecant of each entry of G. +% Since csch(0) is nonzero, C is a full matrix. +% +% See also GrB/csc, GrB/acsc, GrB/acsch. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +if (~gb_isfloat (gbtype (G))) + op = 'sinh.double' ; +else + op = 'sinh' ; +end + +C = GrB (gbapply ('minv', gbfull (gbapply (op, G)))) ; + diff --git a/GraphBLAS/@GrB/ctranspose.m b/GraphBLAS/@GrB/ctranspose.m index 3ff375952f..b8bb37030b 100644 --- a/GraphBLAS/@GrB/ctranspose.m +++ b/GraphBLAS/@GrB/ctranspose.m @@ -1,12 +1,18 @@ function C = ctranspose (G) %CTRANSPOSE C = G', transpose a GraphBLAS matrix. -% Note that complex matrices are not yet supported. When they are, this -% will compute the complex conjugate transpose C=G' when G is complex. +% C = G' is the complex conjugate transpose of G. % -% See also GrB.trans, transpose. +% See also GrB.trans, GrB/transpose, GrB/conj. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB.trans (G) ; +G = G.opaque ; + +if (contains (gbtype (G), 'complex')) + desc.in0 = 'transpose' ; + C = GrB (gbapply ('conj', G, desc)) ; +else + C = GrB (gbtrans (G)) ; +end diff --git a/GraphBLAS/@GrB/descriptorinfo.m b/GraphBLAS/@GrB/descriptorinfo.m index 042d933176..b3eeeb0f3c 100644 --- a/GraphBLAS/@GrB/descriptorinfo.m +++ b/GraphBLAS/@GrB/descriptorinfo.m @@ -1,33 +1,30 @@ function descriptorinfo (d) %GRB.DESCRIPTOR list the contents of a SuiteSparse:GraphBLAS descriptor. % -% Usage: -% % GrB.descriptorinfo % GrB.descriptorinfo (d) % -% The GraphBLAS descriptor is a MATLAB struct that can be used to modify -% the behavior of GraphBLAS operations. It contains the following -% components, each of which are a string or a number. Any component of -% struct that is not present is set to the default value. If the -% descriptor d is empty, or not present, in a GraphBLAS function, all -% default settings are used. +% The GraphBLAS descriptor is a MATLAB struct that modifies the behavior +% of GraphBLAS operations. It contains the following components, each of +% which are a string or a number. Any component of struct that is not +% present is set to the default value. If the descriptor d is empty, or +% not present, in a GraphBLAS function, all default settings are used. % % The following descriptor values are strings: % % d.out 'default' or 'replace' determines if C is cleared before -% the accum/mask step +% the accum/mask step % -% d.mask 'default' use M as the mask (if present) -% 'complement' use ~M as the mask -% 'structural' or 'structure' use the pattern of M, not its values -% 'structural complement' use the pattern of ~M +% d.mask 'default' use M as the mask (if present) +% 'complement' use ~M as the mask +% 'structural' or 'structure' use the pattern of M +% 'structural complement' use the pattern of ~M % -% d.in0 'default' or 'transpose' determines A or A' is used -% d.in1 'default' or 'transpose' determines B or B' is used +% d.in0 'default' or 'transpose' determines A or A.' is used +% d.in1 'default' or 'transpose' determines B or B.' is used % -% d.axb 'default', 'Gustavson', 'heap', 'hash', or 'dot'. Determines the -% method used in GrB.mxm. The default is to let GraphBLAS +% d.axb 'default', 'saxpy', 'dot', 'Gustavson', or 'hash'. Determines +% the method used in GrB.mxm. The default is to let GraphBLAS % determine the method automatically, via a heuristic. % % d.kind For most GrB.methods, this is a string equal to 'default', @@ -35,11 +32,11 @@ function descriptorinfo (d) % where the GraphBLAS operation returns an object, which is % preferred since GraphBLAS sparse matrices are faster and can % represent many more data types. However, if you want a -% standard MATLAB sparse matrix, use d.kind='sparse'. Use -% d.kind='full' for a MATLAB dense matrix. For any GrB.method -% that takes a descriptor, the following uses are the same, -% but the first method is faster and takes less temporary -% workspace: +% standard MATLAB sparse matrix on ouput, use d.kind='sparse'. +% Use d.kind='full' to return a MATLAB dense matrix. For any +% GrB.method that takes a descriptor, the following uses are +% the same, but the first method is faster and takes less +% temporary workspace: % % d.kind = 'sparse' ; % S = GrB.method (..., d) ; @@ -47,27 +44,27 @@ function descriptorinfo (d) % % with no d, or d.kind = 'default' % S = double (GrB.method (...)) : % -% d.base A string equal to 'default', 'zero-based', 'one-based', -% or 'one-based int'. The default is 'one-based'. If d.base is -% 'zero-based', then indices are zero-based, in the range 0 to n-1, -% for a matrix of dimension n. +% d.base A string equal to 'default', 'zero-based', 'one-based', or +% 'one-based int'. The default is 'one-based'. If d.base is +% 'zero-based', then indices are zero-based, in the range 0 to +% n-1, for a matrix of dimension n. % % d.format a string, either 'by row' or 'by col', which defines the -% format of the GraphBLAS output matrix C. The following rules -% are used to determine the format of the result, in order: -% -% (1) If the format is determined by the descriptor to the -% method, then that determines the format of C. -% (2) If C is a column vector then C is stored by column. -% (3) If C is a row vector then C is stored by row. -% (4) If the method has a first matrix input (usually called A), -% and it is not a row or column vector, then its format is -% used for C. -% (5) If the method has a second matrix input (usually called -% B), and it is not a row or column vector, then its format -% is used for C. -% (6) Otherwise, the global default format is used for C. -% See GrB.format for details. +% format of the GraphBLAS output matrix C. The following rules +% are used to determine the format of the result, in order: +% +% (1) If the format is determined by the descriptor to the +% method, then that determines the format of C. +% (2) If C is a column vector then C is stored by column. +% (3) If C is a row vector then C is stored by row. +% (4) If the method has a first matrix input (usually called A), +% and it is not a row or column vector, then its format is +% used for C. +% (5) If the method has a second matrix input (usually called +% B), and it is not a row or column vector, then its format +% is used for C. +% (6) Otherwise, the global default format is used for C. +% See GrB.format for details. % % These descriptor values are scalars: % @@ -81,8 +78,10 @@ function descriptorinfo (d) % See also GrB.binopinfo, GrB.monoidinfo, GrB.selectopinfo, % GrB.semiringinfo, GrB.unopinfo. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +% FUTURE: add desc.in* = 'conjugate transpose' if (nargin == 0) help GrB.descriptorinfo diff --git a/GraphBLAS/@GrB/diag.m b/GraphBLAS/@GrB/diag.m index e5bce1b671..179bccf88c 100644 --- a/GraphBLAS/@GrB/diag.m +++ b/GraphBLAS/@GrB/diag.m @@ -1,18 +1,18 @@ -function C = diag (G, k) -%DIAG Diagonal matrices and diagonals of a GraphBLAS matrix. -% C = diag (v,k) when v is a GraphBLAS vector with n components is a -% square sparse GarphBLAS matrix of dimension n+abs(k), with the elements -% of v on the kth diagonal. The main diagonal is k = 0; k > 0 is above -% the diagonal, and k < 0 is below the main diagonal. C = diag (v) is -% the same as C = diag (v,0). +function C = diag (A, k) +%DIAG diagonal matrices and diagonals of a matrix. +% C = diag (v,k) when v is a vector with n components is a square sparse +% matrix of dimension n+abs(k), with the elements of v on the kth +% diagonal. The main diagonal is k = 0; k > 0 is above the diagonal, and +% k < 0 is below the main diagonal. C = diag (v) is the same as +% C = diag (v,0). % -% c = diag (G,k) when G is a GraphBLAS matrix returns a GraphBLAS column -% vector c formed the entries on the kth diagonal of G. The main -% diagonal is c = diag(G). +% c = diag (A,k) when A is a matrix returns a column vector c formed the +% entries on the kth diagonal of A. The main diagonal is c = diag (A). % -% The GraphBLAS diag function always constructs a GraphBLAS sparse -% matrix, unlike the the MATLAB diag, which always constructs a MATLAB -% full matrix. +% The GraphBLAS diag function always constructs a GraphBLAS sparse matrix, +% unlike the built-in MATLAB diag, which always constructs a MATLAB full +% matrix. To use this overloaded function for a MATLAB sparse matrix A, +% use C = diag (A, GrB (k)) ; % % Examples: % @@ -29,48 +29,20 @@ % G = diag(GrB(-m:m)) + diag(GrB(f),1) + diag(GrB(f),-1) % nothing = double (A-G) % -% See also diag, spdiags, tril, triu, GrB.select. +% See also GrB/diag, spdiags, GrB/tril, GrB/triu, GrB.select. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -if (nargin < 2) - k = 0 ; +if (isobject (A)) + A = A.opaque ; end -[am, an] = size (G) ; -isvec = (am == 1) || (an == 1) ; -desc.base = 'zero-based' ; -if (isvec) - % C = diag (v,k) is an m-by-m matrix - if (am == 1) - % convert G to a column vector - v = G.' ; - else - v = G ; - end - n = length (v) ; - m = n + abs (k) ; - if (k >= 0) - [I, ~, X] = GrB.extracttuples (v, desc) ; - J = I + int64 (k) ; - else - [J, ~, X] = GrB.extracttuples (v, desc) ; - I = J - int64 (k) ; - end - C = GrB.build (I, J, X, m, m, desc) ; +if (nargin < 2) + k = 0 ; else - % C = diag (G,k) is a column vector formed from the elements of the kth - % diagonal of G - C = GrB.select ('diag', G, k) ; - if (k >= 0) - [I, ~, X] = GrB.extracttuples (C, desc) ; - m = min (an-k, am) ; - else - [~, I, X] = GrB.extracttuples (C, desc) ; - m = min (an, am+k) ; - end - J = zeros (length (X), 1, 'int64') ; - C = GrB.build (I, J, X, m, 1, desc) ; + k = gb_get_scalar (k) ; end +C = GrB (gb_diag (A, k)) ; + diff --git a/GraphBLAS/@GrB/digraph.m b/GraphBLAS/@GrB/digraph.m index 7bf84ff6a4..e0ee76db97 100644 --- a/GraphBLAS/@GrB/digraph.m +++ b/GraphBLAS/@GrB/digraph.m @@ -1,14 +1,14 @@ function DiGraph = digraph (G, option) -%GRAPH convert a GraphBLAS matrix into a MATLAB directed DiGraph. -% DiGraph = digraph (G) converts a GraphBLAS matrix G into a directed MATLAB -% DiGraph. G must be square. If G is logical, then no weights are added to -% the DiGraph. If G is single or double, these become the weights of the -% MATLAB DiGraph. If G is integer, the DiGraph is constructed with weights of -% type double. An optional string argument can appear after G: +%DIGRAPH convert a GraphBLAS matrix into a MATLAB directed DiGraph. +% DiGraph = digraph (G) converts a GraphBLAS matrix G into a directed +% MATLAB DiGraph. G must be square. If G is logical, then no weights are +% added to the DiGraph. If G is single or double, these become the weights +% of the MATLAB DiGraph. If G is integer, the DiGraph is constructed with +% weights of type double. % -% DiGraph = digraph (G, 'omitselfloops') ignores the diagonal of G, and the -% resulting MATLAB DiGraph has no self-edges. The default is that self-edges -% are created from any diagonal entries of G. +% DiGraph = digraph (G, 'omitselfloops') ignores the diagonal of G, and the +% resulting MATLAB DiGraph has no self-edges. The default is that +% self-edges are created from any diagonal entries of G. % % Example: % @@ -22,15 +22,16 @@ % t = title ('random directed graph with 8 nodes') ; % t.FontSize = 20 ; % -% See also graph, digraph, GrB/graph, plot. +% See also graph, digraph, GrB/graph. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -type = GrB.type (G) ; -[m, n] = size (G) ; +G = G.opaque ; + +[m, n, type] = gbsize (G) ; if (m ~= n) - gb_error ('G must be square') ; + error ('G must be square') ; end % get the string options @@ -39,26 +40,35 @@ if (isequal (lower (option), 'omitselfloops')) omitself = true ; else - gb_error ('unknown option') ; + error ('unknown option') ; end end % apply the options if (omitself) % ignore diagonal entries of G - G = GrB.offdiag (G) ; + G = gbselect ('offdiag', G, 0) ; end % construct the digraph -if (isequal (type, 'logical')) - DiGraph = digraph (logical (G)) ; -elseif (isequal (type, 'double')) - DiGraph = digraph (double (G)) ; -elseif (isequal (type, 'single')) - [i, j, x] = GrB.extracttuples (G) ; - DiGraph = digraph (i, j, x, n) ; -else - % all other types (int* and uint*) must be cast to double - DiGraph = digraph (double (GrB (G, 'double'))) ; +switch (type) + + case { 'single' } + + % The MATLAB digraph(...) function can accept x as single, but not + % from a MATLAB sparse matrix. So extract the tuples of G first. + [i, j, x] = gbextracttuples (G) ; + DiGraph = digraph (i, j, x, n) ; + + case { 'logical' } + + % The MATLAB digraph(...) function allows for sparse logical + % adjacency matrices (no edge weights are created). + DiGraph = digraph (gbsparse (G, 'logical')) ; + + otherwise + + % typecast to double + DiGraph = digraph (gbsparse (G, 'double')) ; end diff --git a/GraphBLAS/@GrB/disp.m b/GraphBLAS/@GrB/disp.m index 51cf9bdd88..305fd71e5e 100644 --- a/GraphBLAS/@GrB/disp.m +++ b/GraphBLAS/@GrB/disp.m @@ -1,17 +1,38 @@ -function disp (G, level) -%DISP display the contents of a GraphBLAS matrix. -% disp (G, level) displays the GraphBLAS sparse matrix G. Level controls -% how much is printed; 0: none, 1: terse, 2: a few entries, 3: all. The -% default is 2 if level is not present. +function disp (A, level) +%DISP display the contents of a MATLAB or GraphBLAS matrix. +% disp (A, level) displays the matrix A. The 2nd argument controls how +% much is printed; 0: none, 1: terse, 2: a few entries, 3: all, 4: a few +% entries with high precision, 5: all with high precision. The default is +% 2 if level is not present. To use this function on a MATLAB sparse +% matrix, use disp (A, GrB (level)). This is useful since disp(A) will +% always display all entries of A, which can be too verbose if nnz (A) +% is huge. % -% See also display. +% Example: +% +% A = sprand (50, 50, 0.1) ; +% % just print a few entries +% disp (A, GrB (2)) +% G = GrB (A) +% % print all entries +% A +% disp (G, 3) +% % print all entries in full precision +% format long +% A +% disp (G, 5) +% +% See also GrB/display. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. if (nargin < 2) level = 2 ; +else + level = gb_get_scalar (level) ; end + if (level > 0) name = inputname (1) ; if (~isempty (name)) @@ -19,5 +40,14 @@ function disp (G, level) end end -gbdisp (G.opaque, nnz (G), level) ; +if (isobject (A)) + A = A.opaque ; + gbdisp (A, gb_nnz (A), level) ; +else + gbdisp (A, nnz (A), level) ; +end + +if (level > 0) + fprintf ('\n') ; +end diff --git a/GraphBLAS/@GrB/display.m b/GraphBLAS/@GrB/display.m index c2686b7041..607c95831a 100644 --- a/GraphBLAS/@GrB/display.m +++ b/GraphBLAS/@GrB/display.m @@ -4,14 +4,16 @@ function display (G) %#ok % GraphBLAS sparse matrix object. Use disp(G,3) to display all of the % content of G. % -% See also disp. +% See also GrB/disp. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. name = inputname (1) ; if (~isempty (name)) fprintf ('\n%s =\n', name) ; end -gbdisp (G.opaque, nnz (G), 2) ; +G = G.opaque ; +gbdisp (G, gb_nnz (G), 2) ; +fprintf ('\n') ; diff --git a/GraphBLAS/@GrB/dmperm.m b/GraphBLAS/@GrB/dmperm.m index 5fabade3aa..d648bd9202 100644 --- a/GraphBLAS/@GrB/dmperm.m +++ b/GraphBLAS/@GrB/dmperm.m @@ -1,11 +1,11 @@ function [p, varargout] = dmperm (G) -%DMPERM Dulmage-Mendelsohn permutation of a GraphBLAS matrix. +%DMPERM Dulmage-Mendelsohn permutation. % See 'help dmperm' for details. % -% See also amd, colamd. +% See also GrB/amd, GrB/colamd. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. [p, varargout{1:nargout-1}] = builtin ('dmperm', logical (G)) ; diff --git a/GraphBLAS/@GrB/dnn.m b/GraphBLAS/@GrB/dnn.m index d7145aca08..b28e26d945 100644 --- a/GraphBLAS/@GrB/dnn.m +++ b/GraphBLAS/@GrB/dnn.m @@ -1,24 +1,25 @@ function Y = dnn (W, bias, Y0) %GRB.DNN Sparse deep neural network in GraphBLAS. -% Performs ReLU inference using input feature vector(s) Y0, DNN weights W, and -% bias vectors. The input features are in a matrix Y0 of size nfeatures-by- -% nneurons. The DNN weights W is a cell array with W{k} being the kth layer of -% the DNN, so that the number of layers is nlayers = length (W). W{k} is a -% matrix of size nneurons-by-nneurons. The bais variable is a cell array of -% length nlayers. Each bias{k} is a diagonal matrix of size nneurons-by- -% nneurons, which gives the bias values of each neuron in the kth layer. +% Performs ReLU inference using input feature vector(s) Y0, DNN weights W, +% and bias vectors. The input features are in a matrix Y0 of size +% nfeatures-by- nneurons. The DNN weights W is a cell array with W{k} +% being the kth layer of the DNN, so that the number of layers is nlayers = +% length (W). W{k} is a matrix of size nneurons-by-nneurons. The bias +% variable is a cell array of length nlayers. Each bias{k} is a diagonal +% matrix of size nneurons-by-nneurons, which gives the bias values of each +% neuron in the kth layer. % % Usage: % % Y = GrB.dnn (W, bias, Y0) ; % % The matrices can be stored by row or by column, but GrB.format ('by row') -% is significantly faster. For the 2019 GraphChallenge, all matrices can be -% 'single', and the same results are obtained. +% is significantly faster. For the 2019 GraphChallenge, all matrices can +% be 'single', and the same results are obtained. % -% In the MATLAB reference implementation, the bias{k} is a row vector of size -% 1-by-nneurons. The MATLAB reference inputs can be converted to GraphBLAS -% matrices with the following code: +% In the MATLAB reference implementation, the bias{k} is a row vector of +% size 1-by-nneurons. The MATLAB reference inputs can be converted to +% GraphBLAS matrices with the following code: % % d = struct ('format', 'by row') ; % n = size (Y0, 2) ; @@ -33,8 +34,10 @@ % % See also dnn_matlab, dnn_mat2gb. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +% NOTE: this is a high-level algorithm that uses GrB objects. Y = Y0 ; for k = 1:length(W) diff --git a/GraphBLAS/@GrB/double.m b/GraphBLAS/@GrB/double.m index 3446083994..dca55663b2 100644 --- a/GraphBLAS/@GrB/double.m +++ b/GraphBLAS/@GrB/double.m @@ -1,21 +1,23 @@ function C = double (G) %DOUBLE cast a GraphBLAS sparse matrix to a MATLAB sparse double matrix. % C = double (G) typecasts the GraphBLAS matrix G into a MATLAB sparse -% double matrix C, either real or complex. +% double matrix C, either real or complex. Explicit zeros are dropped. % % To typecast the matrix G to a GraphBLAS sparse double (real) matrix -% instead, use C = GrB (G, 'double'). +% instead, use C = GrB (G, 'double'). Explicit zeros are kept in C. % -% See also cast, GrB, complex, single, logical, int8, int16, int32, int64, -% uint8, uint16, uint32, and uint64. +% See also GrB/cast, GrB, GrB/complex, GrB/single, GrB/logical, GrB/int8, +% GrB/int16, GrB/int32, GrB/int64, GrB/uint8, GrB/uint16, GrB/uint32, +% GrB/uint64. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% if (isreal (G)) - C = gbsparse (G.opaque, 'double') ; -% else -% FUTURE: complex support -% C = gbsparse (G.opaque, 'complex') ; -% end +G = G.opaque ; + +if (contains (gbtype (G), 'complex')) + C = gbsparse (G, 'double complex') ; +else + C = gbsparse (G, 'double') ; +end diff --git a/GraphBLAS/@GrB/eadd.m b/GraphBLAS/@GrB/eadd.m index 0262234757..72d62b5b4d 100644 --- a/GraphBLAS/@GrB/eadd.m +++ b/GraphBLAS/@GrB/eadd.m @@ -1,12 +1,11 @@ -function Cout = eadd (varargin) +function C = eadd (arg1, arg2, arg3, arg4, arg5, arg6, arg7) %GRB.EADD sparse matrix addition. % -% Usage: -% -% Cout = GrB.eadd (op, A, B, desc) -% Cout = GrB.eadd (Cin, accum, op, A, B, desc) -% Cout = GrB.eadd (Cin, M, op, A, B, desc) -% Cout = GrB.eadd (Cin, M, accum, op, A, B, desc) +% C = GrB.eadd (op, A, B) +% C = GrB.eadd (op, A, B, desc) +% C = GrB.eadd (Cin, accum, op, A, B, desc) +% C = GrB.eadd (Cin, M, op, A, B, desc) +% C = GrB.eadd (Cin, M, accum, op, A, B, desc) % % GrB.eadd computes the element-wise 'addition' T=A+B. The result T has % the pattern of the union of A and B. The operator is used where A(i,j) @@ -23,22 +22,52 @@ % T is then accumulated into C via C<#M,replace> = accum (C,T). % % Cin, M, accum, and the descriptor desc are the same as all other -% GrB.methods; see GrB.mxm and GrB.descriptorinfo for more details. For the -% binary operator, see GrB.binopinfo. -% -% All input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. Cout is returned as a GraphBLAS matrix, by default; -% see 'help GrB/descriptorinfo' for more options. +% GrB.methods; see GrB.mxm and GrB.descriptorinfo for more details. For +% the binary operator, see GrB.binopinfo. % % See also GrB.emult. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (arg1)) + arg1 = arg1.opaque ; +end + +if (isobject (arg2)) + arg2 = arg2.opaque ; +end + +if (isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +if (nargin > 4 && isobject (arg5)) + arg5 = arg5.opaque ; +end + +if (nargin > 5 && isobject (arg6)) + arg6 = arg6.opaque ; +end + +switch (nargin) + case 3 + [C, k] = gbeadd (arg1, arg2, arg3) ; + case 4 + [C, k] = gbeadd (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbeadd (arg1, arg2, arg3, arg4, arg5) ; + case 6 + [C, k] = gbeadd (arg1, arg2, arg3, arg4, arg5, arg6) ; + case 7 + [C, k] = gbeadd (arg1, arg2, arg3, arg4, arg5, arg6, arg7) ; +end -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - Cout = GrB (gbeadd (args {:})) ; -else - Cout = gbeadd (args {:}) ; +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/eig.m b/GraphBLAS/@GrB/eig.m index e4ca178da9..61cae9ca79 100644 --- a/GraphBLAS/@GrB/eig.m +++ b/GraphBLAS/@GrB/eig.m @@ -4,9 +4,12 @@ % % See also eigs. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. +% NOTE: this is a high-level algorithm that uses GrB objects. + +% convert G to a MATLAB matrix if (isreal (G) && issymmetric (G)) % G can be sparse if G is real and symmetric G = double (G) ; @@ -14,13 +17,16 @@ % otherwise, G must be full. G = full (double (G)) ; end + +% use the built-in eig if (nargin == 1) [V, varargout{1:nargout-1}] = builtin ('eig', G) ; else args = varargin ; for k = 1:length (args) - if (isa (args {k}, 'GrB')) - args {k} = full (double (args {k})) ; + argk = args {k} ; + if (isobject (argk)) + args {k} = full (double (argk)) ; end end [V, varargout{1:nargout-1}] = builtin ('eig', G, args {:}) ; diff --git a/GraphBLAS/@GrB/empty.m b/GraphBLAS/@GrB/empty.m index 4c7ac8c707..0ea625cdbd 100644 --- a/GraphBLAS/@GrB/empty.m +++ b/GraphBLAS/@GrB/empty.m @@ -1,39 +1,29 @@ -function C = empty (arg1, arg2) +function C = empty (varargin) %GRB.EMPTY construct an empty GraphBLAS sparse matrix. % C = GrB.empty is a 0-by-0 empty matrix. % C = GrB.empty (m) is an m-by-0 empty matrix. -% C = GrB.empty ([m n]) or GrB.empty (m,n) is an m-by-n empty matrix, where -% one of m or n must be zero. +% C = GrB.empty ([m n]) or GrB.empty (m,n) is an m-by-n empty matrix, +% where one of m or n must be zero. % % All matrices are constructed with the 'double' type. Use GrB (m,n,type) -% to construct empty single, int*, uint*, and logical m-by-n matrices. +% to construct empty matrices of with different types. % % See also GrB. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -m = 0 ; -n = 0 ; -if (nargin == 1) - if (length (arg1) == 1) - m = 0 ; - n = arg1 (1) ; - elseif (length (arg1) == 2) - m = arg1 (1) ; - n = arg1 (2) ; - else - gb_error ('invalid dimensions') ; - end +if (nargin == 0) + m = 0 ; + n = 0 ; else - m = arg1 ; - n = arg2 ; -end -m = max (m, 0) ; -n = max (n, 0) ; -if (~ ((m == 0) || (n == 0))) - gb_error ('at least one dimension must be zero') ; + [m, n] = gb_parse_dimensions (varargin {:}) ; + m = max (m, 0) ; + n = max (n, 0) ; + if (~ ((m == 0) || (n == 0))) + error ('at least one dimension must be zero') ; + end end -C = GrB (m, n) ; +C = GrB (gbnew (m, n)) ; diff --git a/GraphBLAS/@GrB/emult.m b/GraphBLAS/@GrB/emult.m index c08c495db6..1266836352 100644 --- a/GraphBLAS/@GrB/emult.m +++ b/GraphBLAS/@GrB/emult.m @@ -1,12 +1,10 @@ -function Cout = emult (varargin) +function C = emult (arg1, arg2, arg3, arg4, arg5, arg6, arg7) %GRB.EMULT sparse element-wise 'multiplication'. % -% Usage: -% -% Cout = GrB.emult (op, A, B, desc) -% Cout = GrB.emult (Cin, accum, op, A, B, desc) -% Cout = GrB.emult (Cin, M, op, A, B, desc) -% Cout = GrB.emult (Cin, M, accum, op, A, B, desc) +% C = GrB.emult (op, A, B, desc) +% C = GrB.emult (Cin, accum, op, A, B, desc) +% C = GrB.emult (Cin, M, op, A, B, desc) +% C = GrB.emult (Cin, M, accum, op, A, B, desc) % % GrB.emult computes the element-wise 'multiplication' T=A.*B. The result % T has the pattern of the intersection of A and B. The operator is used @@ -18,23 +16,53 @@ % % T is then accumulated into C via C<#M,replace> = accum (C,T). % -% Cin, M, accum, and the descriptor desc are the same as all other +% Cin, M, accum, and the optional descriptor desc are the same as all other % GrB.methods; see GrB.mxm and GrB.descriptorinfo for more details. For the % binary operator, see GrB.binopinfo. % -% All input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. Cout is returned as a GraphBLAS matrix, by default; -% see 'help GrB/descriptorinfo' for more options. -% % See also GrB.eadd. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (arg1)) + arg1 = arg1.opaque ; +end + +if (isobject (arg2)) + arg2 = arg2.opaque ; +end + +if (nargin > 2 && isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +if (nargin > 4 && isobject (arg5)) + arg5 = arg5.opaque ; +end + +if (nargin > 5 && isobject (arg6)) + arg6 = arg6.opaque ; +end + +switch (nargin) + case 3 + [C, k] = gbemult (arg1, arg2, arg3) ; + case 4 + [C, k] = gbemult (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbemult (arg1, arg2, arg3, arg4, arg5) ; + case 6 + [C, k] = gbemult (arg1, arg2, arg3, arg4, arg5, arg6) ; + case 7 + [C, k] = gbemult (arg1, arg2, arg3, arg4, arg5, arg6, arg7) ; +end -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - Cout = GrB (gbemult (args {:})) ; -else - Cout = gbemult (args {:}) ; +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/end.m b/GraphBLAS/@GrB/end.m index ca6870a2b1..023105801a 100644 --- a/GraphBLAS/@GrB/end.m +++ b/GraphBLAS/@GrB/end.m @@ -1,23 +1,23 @@ function i = end (G, k, ndims) %END Last index in an indexing expression for a GraphBLAS matrix. % -% See also size, length. +% See also GrB/size, GrB/length. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. % FUTURE: add linear indexing % FUTURE: use hypersparse matrices to implement multidimensionl nD arrays if (ndims == 1) if (~isvector (G)) - error ('GrB:unsupported', 'Linear indexing not supported') ; + error ('Linear indexing not yet supported') ; end i = length (G) ; elseif (ndims == 2) s = size (G) ; i = s (k) ; else - error ('GrB:unsupported', '%dD indexing not supported', ndims) ; + error ('%dD indexing not yet supported', ndims) ; end diff --git a/GraphBLAS/@GrB/entries.m b/GraphBLAS/@GrB/entries.m index abbc387061..50ca805fa7 100644 --- a/GraphBLAS/@GrB/entries.m +++ b/GraphBLAS/@GrB/entries.m @@ -9,7 +9,7 @@ % of zero (or any specified additive identity value) use GrB.nonz % instead. % -% let [m n] = size (A) +% Let [m n] = size (A) % % e = GrB.entries (A) number of entries % e = GrB.entries (A, 'all') number of entries @@ -33,6 +33,9 @@ % then d(j) is an implicit zero, not present in the pattern of d, so % that I = find (d) is the same I = GrB.entries (A, 'col', 'list'). % +% The result is a MATLAB scalar or vector, except for the 'degree' +% usage, in which case the result is a GrB vector d. +% % Example: % % A = magic (5) ; @@ -49,75 +52,19 @@ % % See also GrB.nonz, nnz, GrB/nnz, nonzeros, GrB/nonzeros. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% get the string arguments -dim = 'all' ; % 'all', 'row', or 'col' -kind = 'count' ; % 'count', 'list', or 'degree' -for k = 1:nargin-1 - arg = varargin {k} ; - switch arg - case { 'all', 'row', 'col' } - dim = arg ; - case { 'count', 'list', 'degree' } - kind = arg ; - otherwise - gb_error ('unknown option') ; - end +if (isobject (A)) + % A is a GraphBLAS matrix; get its opaque content + A = A.opaque ; end -if (isequal (dim, 'all')) - - switch kind - case 'count' - % number of entries in A - % e = GrB.entries (A) - if (isa (A, 'GrB')) - result = gbnvals (A.opaque) ; - else - result = gbnvals (A) ; - end - case 'list' - % list of values of unique entries - % X = GrB.entries (A, 'list') - if (isa (A, 'GrB')) - result = unique (gbextractvalues (A.opaque)) ; - else - result = unique (gbextractvalues (A)) ; - end - otherwise - gb_error ('''all'' and ''degree'' cannot be combined') ; - end - -else - - % get the row or column degree - f = GrB.format (A) ; - native = (isequal (f, 'by row') && isequal (dim, 'row')) || ... - (isequal (f, 'by col') && isequal (dim, 'col')) ; - if (isa (A, 'GrB')) - degree = GrB (gbdegree (A.opaque, native)) ; - else - degree = GrB (gbdegree (A, native)) ; - end +% get the count/list of the entries of A +result = gb_entries (A, varargin {:}) ; - switch kind - case 'count' - % number of non-empty rows/cols - % e = GrB.entries (A, 'row') - % e = GrB.entries (A, 'col') - result = nnz (degree) ; - case 'list' - % list of non-empty rows/cols - % I = GrB.entries (A, 'row', 'list') - % J = GrB.entries (A, 'col', 'list') - result = find (degree) ; - case 'degree' - % degree of all rows/cols - % d = GrB.entries (A, 'row', 'degree') - % d = GrB.entries (A, 'col', 'degree') - result = degree ; - end +% if gb_entries returned a GraphBLAS struct, return it as a GrB matrix +if (isstruct (result)) + result = GrB (result) ; end diff --git a/GraphBLAS/@GrB/eps.m b/GraphBLAS/@GrB/eps.m index e0374ca54d..60ff204e4c 100644 --- a/GraphBLAS/@GrB/eps.m +++ b/GraphBLAS/@GrB/eps.m @@ -1,19 +1,34 @@ function C = eps (G) -%EPS Spacing of floating-point numbers in a GraphBLAS matrix. +%EPS spacing of numbers in a GraphBLAS matrix. +% C = eps (G) returns the spacing of numbers in a floating-point GraphBLAS +% matrix. % -% See also isfloat, realmax, realmin. +% See also GrB/isfloat, realmax, realmin. -% FUTURE: this will be much faster as a mexFunction. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% FUTURE: GraphBLAS should have a built-in unary operator to +% compute eps. -if (~isfloat (G)) - gb_error ('Type must be ''single'', ''double'', or ''complex''') ; -end +% convert to a MATLAB full matrix and use the MATLAB eps: + +switch (GrB.type (G)) + + case { 'single' } + C = GrB (eps (single (full (G)))) ; + + case { 'double' } + C = GrB (eps (double (full (G)))) ; -[m, n] = size (G) ; -desc.base = 'zero-based' ; -[i, j, x] = GrB.extracttuples (full (G), desc) ; -C = GrB.build (i, j, eps (x), m, n, desc) ; + case { 'single complex' } + C = max (eps (single (real (G))), eps (single (imag (G)))) ; + + case { 'double complex' } + C = max (eps (double (real (G))), eps (double (imag (G)))) ; + + otherwise + error ('input must be floating-point') ; + +end diff --git a/GraphBLAS/@GrB/eq.m b/GraphBLAS/@GrB/eq.m index 3a01caabbe..51b6efc48f 100644 --- a/GraphBLAS/@GrB/eq.m +++ b/GraphBLAS/@GrB/eq.m @@ -1,5 +1,5 @@ function C = eq (A, B) -%A == B Equal. +%A == B equal. % C = (A == B) is an element-by-element comparison of A and B. One or % both may be scalars. Otherwise, A and B must have the same size. % @@ -8,61 +8,64 @@ % % See also GrB/lt, GrB/le, GrB/gt, GrB/ge, GrB/ne. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. % The pattern of C depends on the type of inputs: % A scalar, B scalar: C is scalar. % A scalar, B matrix: C is full if A==0, otherwise C is a subset of B. % B scalar, A matrix: C is full if B==0, otherwise C is a subset of A. % A matrix, B matrix: C is full. -% Zeroes are then dropped from C after it is computed. -if (isscalar (A)) - if (isscalar (B)) +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +[am, an, atype] = gbsize (A) ; +[bm, bn, btype] = gbsize (B) ; +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; +ctype = gboptype (atype, btype) ; + +if (a_is_scalar) + if (b_is_scalar) % both A and B are scalars. C is full. - C = gb_dense_comparator (A, '==', B) ; + C = GrB (gbemult (gbfull (A, ctype), '==', gbfull (B, ctype))) ; else % A is a scalar, B is a matrix - if (gb_get_scalar (A) == 0) + if (gb_scalar (A) == 0) % since a == 0, entries not present in B result in a true % value, so the result is dense. Expand A to a dense matrix. - [m, n] = size (B) ; - % A (1:m,1:n) = A, and cast to the type of B - A = GrB.subassign (GrB (m, n, GrB.type (B)), A) ; - if (~GrB.isfull (B)) - B = full (B) ; - end - C = GrB.emult (A, '==', B) ; + A = gb_scalar_to_full (bm, bn, ctype, A) ; + C = GrB (gbemult (A, '==', gbfull (B, ctype))) ; else % since a ~= 0, entries not present in B result in a false % value, so the result is a sparse subset of B. select all % entries in B == a, then convert to true. - C = GrB.apply ('1.logical', GrB.select (B, '==', A)) ; + C = GrB (gbapply ('1.logical', gbselect (B, '==', A))) ; end end else - if (isscalar (B)) + if (b_is_scalar) % A is a matrix, B is a scalar - if (gb_get_scalar (B) == 0) + if (gb_scalar (B) == 0) % since b == 0, entries not present in A result in a true % value, so the result is dense. Expand B to a dense matrix. - [m, n] = size (A) ; - % B (1:m,1:n) = B and cast to the type of A - B = GrB.subassign (GrB (m, n, GrB.type (A)), B) ; - if (~GrB.isfull (A)) - A = full (A) ; - end - C = GrB.emult (A, '==', B) ; + B = gb_scalar_to_full (am, an, ctype, B) ; + C = GrB (gbemult (gbfull (A, ctype), '==', B)) ; else % since b ~= 0, entries not present in A result in a false % value, so the result is a sparse subset of A. select all % entries in A == b, then convert to true. - C = GrB.apply ('1.logical', GrB.select (A, '==', B)) ; + C = GrB (gbapply ('1.logical', gbselect (A, '==', B))) ; end else % both A and B are matrices. C is full. - C = gb_dense_comparator (A, '==', B) ; + C = GrB (gbemult (gbfull (A, ctype), '==', gbfull (B, ctype))) ; end end diff --git a/GraphBLAS/@GrB/erf.m b/GraphBLAS/@GrB/erf.m new file mode 100644 index 0000000000..383bceebd0 --- /dev/null +++ b/GraphBLAS/@GrB/erf.m @@ -0,0 +1,23 @@ +function C = erf (G) +%ERF error function. +% C = erf (G) computes the error function of each entry of G. +% G must be real. +% +% See also GrB/erfc, erfcx, erfinv, erfcinv. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; +if (contains (type, 'complex')) + error ('input must be real') ; +end +if (~gb_isfloat (type)) + op = 'erf.double' ; +else + op = 'erf' ; +end + +C = GrB (gbapply (op, G)) ; + diff --git a/GraphBLAS/@GrB/erfc.m b/GraphBLAS/@GrB/erfc.m new file mode 100644 index 0000000000..36e2c99a85 --- /dev/null +++ b/GraphBLAS/@GrB/erfc.m @@ -0,0 +1,21 @@ +function C = erfc (G) +%ERFC complementary error function. +% C = erfc (G) is the complementary error function of each entry of G. +% Since erfc (0) = 1, the result is a full matrix. G must be real. +% +% See also GrB/erf, erfcx, erfinv, erfcinv. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; +if (contains (type, 'complex')) + error ('input must be real') ; +end +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gbapply ('erfc', gbfull (G, type))) ; + diff --git a/GraphBLAS/@GrB/etree.m b/GraphBLAS/@GrB/etree.m index d388898856..9a71c36e9f 100644 --- a/GraphBLAS/@GrB/etree.m +++ b/GraphBLAS/@GrB/etree.m @@ -1,11 +1,12 @@ function [parent, varargout] = etree (G, varargin) -%ETREE Elimination tree of a GraphBLAS matrix. +%ETREE elimination tree of a GraphBLAS matrix. % See 'help etree' for details. % -% See also amd. +% See also GrB/amd. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -[parent, varargout{1:nargout-1}] = builtin ('etree', logical (G), varargin {:}); +G = logical (G) ; +[parent, varargout{1:nargout-1}] = builtin ('etree', G, varargin {:}) ; diff --git a/GraphBLAS/@GrB/exp.m b/GraphBLAS/@GrB/exp.m new file mode 100644 index 0000000000..b5a86c55a8 --- /dev/null +++ b/GraphBLAS/@GrB/exp.m @@ -0,0 +1,19 @@ +function C = exp (G) +%EXP exponential. +% C = exp (G) is e^x for each entry x of the matrix G. +% Since e^0 is nonzero, C is a full matrix. +% +% See also GrB/exp, GrB/expm1, GrB/pow2, GrB/log, GrB/log10, GrB/log2. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; + +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gbapply ('exp', gbfull (G, type))) ; + diff --git a/GraphBLAS/@GrB/expand.m b/GraphBLAS/@GrB/expand.m index 0f57946101..52a430e0bf 100644 --- a/GraphBLAS/@GrB/expand.m +++ b/GraphBLAS/@GrB/expand.m @@ -1,21 +1,38 @@ -function C = expand (scalar, S) -%GRB.EXPAND expand a scalar into a GraphBLAS matrix. +function C = expand (scalar, S, type) +%GRB.EXPAND expand a scalar into a matrix. % C = GrB.expand (scalar, S) expands the scalar into a matrix with the % same size and pattern as S, as C = scalar*spones(S). C has the same -% type as the scalar. The numerical values of S are ignored; only the -% pattern of S is used. The inputs may be either GraphBLAS and/or -% MATLAB matrices/scalars, in any combination. C is returned as a -% GraphBLAS matrix. +% type as the scalar. C = GrB.expand (scalar, S, type) allows the type of +% C to be specified. The numerical values of S are ignored; only the +% pattern of S is used. +% +% Example: +% A = sprand (4, 4, 0.5) +% C1 = pi * spones (A) +% C2 = GrB.expand (pi, A) +% C3 = GrB.expand (pi, A, 'single complex') % % See also GrB.assign. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (scalar)) + % do not use gb_get_scalar, to keep it sparse + scalar = scalar.opaque ; +end + +if (~gb_isscalar (scalar)) + error ('first input must be a scalar') ; +end + +if (isobject (S)) + S = S.opaque ; +end -% FUTURE: as much as possible, replace scalar expansion with binary operators -% used in a unary apply, when it becomes part of the C API. +if (nargin < 3) + type = gbtype (scalar) ; +end -[m, n] = size (S) ; -desc.mask = 'structure' ; -C = GrB.assign (GrB (m, n, GrB.type (S)), S, scalar, desc) ; +C = GrB (gb_expand (scalar, S, type)) ; diff --git a/GraphBLAS/@GrB/expm1.m b/GraphBLAS/@GrB/expm1.m new file mode 100644 index 0000000000..880b10fbcf --- /dev/null +++ b/GraphBLAS/@GrB/expm1.m @@ -0,0 +1,19 @@ +function C = expm1 (G) +%EXPM1 exp(x)-1. +% C = expm1 (G) computes (e^x)-1 for each entry x of a matrix G. +% +% See also GrB/exp, GrB/expm1, GrB/log, GrB/log10, GrB/log2. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; + +if (~gb_isfloat (gbtype (G))) + op = 'expm1.double' ; +else + op = 'expm1' ; +end + +C = GrB (gbapply (op, G)) ; + diff --git a/GraphBLAS/@GrB/extract.m b/GraphBLAS/@GrB/extract.m index ee89f4e46d..5f15ff3f83 100644 --- a/GraphBLAS/@GrB/extract.m +++ b/GraphBLAS/@GrB/extract.m @@ -1,16 +1,11 @@ -function Cout = extract (varargin) +function C = extract (arg1, arg2, arg3, arg4, arg5, arg6, arg7) %GRB.EXTRACT extract sparse submatrix. % -% GrB.extract is an interface to GrB_Matrix_extract and -% GrB_Matrix_extract_[TYPE], computing the GraphBLAS expression: +% C = GrB.extract (Cin, M, accum, A, I, J, desc) % -% C<#M,replace> = accum (C, A(I,J)) or accum(C, A(J,I)') +% C = A(I,J) or accum (C, A(I,J)) % -% Usage: -% -% Cout = GrB.extract (Cin, M, accum, A, I, J, desc) -% -% A is a required parameters. All others are optional, but if M or accum +% A is a required parameter. All others are optional, but if M or accum % appears, then Cin is also required. If desc.in0 is 'transpose', then % the description below assumes A = A' is computed first before the % extraction (A is not changed on output, however). @@ -48,39 +43,73 @@ % default), then indices are intrepetted as 1-based, just as in MATLAB. % % Cin: an optional input matrix, containing the initial content of the -% matrix C. Cout is the content of C after the assignment is made. -% If present, Cin argument has size length(I)-by-length(J). +% matrix C. C on output is the content of C after the assignment is +% made. If present, Cin argument has size length(I)-by-length(J). % If accum is present then Cin is a required input. % % accum: an optional binary operator, defined by a string ('+.double') for -% example. This allows for Cout = Cin + A(I,J) to be computed. If -% not present, no accumulator is used and Cout=A(I,J) is computed. +% example. This allows for C = Cin + A(I,J) to be computed. If +% not present, no accumulator is used and C=A(I,J) is computed. % If accum is present then Cin is a required input. % % M: an optional mask matrix, the same size as C. % -% All input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. Cout is returned as a GraphBLAS matrix, by default; -% see 'help GrB/descriptorinfo' for more options. -% % Example: % % A = sprand (5, 4, 0.5) % I = [2 1 5] % J = [3 3 1 2] -% Cout = GrB.extract (A, {I}, {J}) +% C = GrB.extract (A, {I}, {J}) % C2 = A (I,J) -% C2 - Cout +% C2 - C % -% See also subsref. +% See also GrB/subsref. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (arg1)) + arg1 = arg1.opaque ; +end + +if (nargin > 1 && isobject (arg2)) + arg2 = arg2.opaque ; +end + +if (nargin > 2 && isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +if (nargin > 4 && isobject (arg5)) + arg5 = arg5.opaque ; +end + +if (nargin > 5 && isobject (arg6)) + arg6 = arg6.opaque ; +end + +switch (nargin) + case 1 + [C, k] = gbextract (arg1) ; + case 2 + [C, k] = gbextract (arg1, arg2) ; + case 3 + [C, k] = gbextract (arg1, arg2, arg3) ; + case 4 + [C, k] = gbextract (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbextract (arg1, arg2, arg3, arg4, arg5) ; + case 6 + [C, k] = gbextract (arg1, arg2, arg3, arg4, arg5, arg6) ; + case 7 + [C, k] = gbextract (arg1, arg2, arg3, arg4, arg5, arg6, arg7) ; +end -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - Cout = GrB (gbextract (args {:})) ; -else - Cout = gbextract (args {:}) ; +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/extracttuples.m b/GraphBLAS/@GrB/extracttuples.m index 03f065eb40..0070304e6e 100644 --- a/GraphBLAS/@GrB/extracttuples.m +++ b/GraphBLAS/@GrB/extracttuples.m @@ -1,18 +1,16 @@ -function [I,J,X] = extracttuples (varargin) +function [I,J,X] = extracttuples (A, desc) %GRB.EXTRACTTUPLES extract a list of entries from a matrix. % -% Usage: -% % [I,J,X] = GrB.extracttuples (A, desc) % -% GrB.extracttuples extracts all entries from either a MATLAB matrix or a -% GraphBLAS matrix. If A is a MATLAB sparse or dense matrix, [I,J,X] = -% GrB.extracttuples (A) is identical to [I,J,X] = find (A). +% GrB.extracttuples extracts all entries from either a MATLAB or +% GraphBLAS matrix. If A is a MATLAB sparse or dense matrix, +% [I,J,X] = GrB.extracttuples (A) is identical to [I,J,X] = find (A). % % For a GraphBLAS matrix G, GrB.extracttuples (G) returns any explicit % zero entries in G, while find (G) excludes them. % -% The descriptor is optional. desc.base is a string, eithe 'default', +% The descriptor is optional. desc.base is a string, either 'default', % 'zero-based', 'one-based int', or 'one-based'. This parameter % determines the type of output for I and J. The default is one-based, % so that I and J are returned as double vectors, with one-based indices. @@ -28,22 +26,26 @@ % conventional 1-based indexing in MATLAB, but it is the fastest method. % % The overloaded [I,J,X] = find (A) method for a GraphBLAS matrix A uses -% desc.base of 'default'. -% -% This function corresponds to the GrB_*_extractTuples_* functions in -% GraphBLAS. +% desc.base of 'default', and always removes explicit zeros. % -% See also find, GrB/build. +% See also GrB/find, GrB/build. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +if (isobject (A)) + A = A.opaque ; +end +if (nargin < 2) + desc.base = 'default' ; +end -[args, ~] = gb_get_args (varargin {:}) ; -if (nargout == 3) - [I, J, X] = gbextracttuples (args {:}) ; -elseif (nargout == 2) - [I, J] = gbextracttuples (args {:}) ; -else - I = gbextracttuples (args {:}) ; +switch (nargout) + case 1 + I = gbextracttuples (A, desc) ; + case 2 + [I, J] = gbextracttuples (A, desc) ; + case 3 + [I, J, X] = gbextracttuples (A, desc) ; end diff --git a/GraphBLAS/@GrB/eye.m b/GraphBLAS/@GrB/eye.m index 4507c05780..0200e35593 100644 --- a/GraphBLAS/@GrB/eye.m +++ b/GraphBLAS/@GrB/eye.m @@ -1,59 +1,17 @@ function C = eye (varargin) -%GRB.EYE Sparse identity matrix, of any type supported by GraphBLAS. -% C = GrB.eye (n) creates a sparse n-by-n identity matrix of type -% 'double'. -% +%GRB.EYE sparse identity matrix. +% C = GrB.eye (n) creates a sparse n-by-n identity matrix of type 'double'. % C = GrB.eye (m,n) or GrB.eye ([m n]) is an m-by-n identity matrix. % % C = GrB.eye (m,n,type) or GrB.eye ([m n],type) creates a sparse m-by-n -% identity matrix C of the given GraphBLAS type, either 'double', -% 'single', 'logical', 'int8', 'int16', 'int32', 'int64', 'uint8', -% 'uint16', 'uint32', 'uint64', or (in the future) 'complex'. +% identity matrix C of the given GraphBLAS type, either 'double', 'single', +% 'logical', 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', +% 'uint32', 'uint64', 'single complex', or 'double complex'. % -% See also spones, spdiags, speye, GrB.speye, GrB. - -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. - -% get the type -type = 'double' ; -nargs = nargin ; -if (nargs > 1 && ischar (varargin {nargs})) - type = varargin {nargs} ; - nargs = nargs - 1 ; -end +% See also GrB/spones, spdiags, GrB.speye, GrB. -% get the size -if (nargs == 0) - m = 1 ; - n = 1 ; -elseif (nargs == 1) - % C = GrB.eye (n) or GrB.eye ([m n]) - arg1 = varargin {1} ; - if (length (arg1) == 1) - % C = GrB.eye (n) - m = arg1 ; - n = m ; - elseif (length (arg1) == 2) - % C = GrB.eye ([m n]) - m = arg1 (1) ; - n = arg1 (2) ; - else - error ('GrB:unsupported', 'only 2D arrays supported') ; - end -elseif (nargs == 2) - % C = GrB.eye (m,n) - m = varargin {1} ; - n = varargin {2} ; -else - error ('GrB:unsupported', 'only 2D arrays supported') ; -end +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% construct the m-by-n identity matrix of the given type -m = max (m, 0) ; -n = max (n, 0) ; -mn = min (m, n) ; -I = int64 (0) : int64 (mn-1) ; -desc.base = 'zero-based' ; -C = GrB.build (I, I, ones (mn, 1, type), m, n, '1st', type, desc) ; +C = GrB (gb_speye ('eye', varargin {:})) ; diff --git a/GraphBLAS/@GrB/false.m b/GraphBLAS/@GrB/false.m index 4ccda31771..515bc8b90d 100644 --- a/GraphBLAS/@GrB/false.m +++ b/GraphBLAS/@GrB/false.m @@ -1,21 +1,22 @@ function C = false (varargin) -%FALSE an all-false GraphBLAS matrix. -% C = false (m, n, 'like', G) or C = false ([m n], 'like', G) constructs -% a logical GraphBLAS matrix of size m-by-n with no entries. +%FALSE a logical matrix with no entries. % -% See also ones, true, zeros. - -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% C = false (n) ; n-by-n GrB logical matrix with no entries. +% C = false (m,n) ; m-by-n GrB logical matrix with no entries. +% C = false ([m,n]) ; m-by-n GrB logical matrix with no entries. +% C = false (..., type) ; empty logical matrix of given type. +% C = false (..., 'like', G) ; empty logical matrix, same type as G. +% +% Since function overloads the MATLAB built-in false(...), at least one +% input must be a GraphBLAS matrix to use this version (for example, +% C = false (GrB (n))). Alternatively, C = GrB (n,n,'logical') can be +% used instead. +% +% See also GrB/ones, GrB/true, GrB/zeros. -arg1 = varargin {1} ; -if (length (arg1) == 2) - m = arg1 (1) ; - n = arg1 (2) ; -else - m = arg1 ; - n = varargin {2} ; -end +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB (m, n, 'logical') ; +[m, n, ~] = gb_parse_args ('false', varargin {:}) ; +C = GrB (gbnew (m, n, 'logical')) ; diff --git a/GraphBLAS/@GrB/finalize.m b/GraphBLAS/@GrB/finalize.m index e3e6921f97..965caf213c 100644 --- a/GraphBLAS/@GrB/finalize.m +++ b/GraphBLAS/@GrB/finalize.m @@ -1,17 +1,15 @@ function finalize %GRB.FINALIZE finalize SuiteSparse:GraphBLAS. % -% Usage: -% % GrB.finalize % % GrB.finalize finishes GraphBLAS, and clears its global settings. % Its use is optional in this version of SuiteSparse:GraphBLAS. % -% See also: GrB.clear, GrB.init +% See also GrB.clear, GrB.init. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. gbsetup ; diff --git a/GraphBLAS/@GrB/find.m b/GraphBLAS/@GrB/find.m index ac4a335dbd..ec978a05eb 100644 --- a/GraphBLAS/@GrB/find.m +++ b/GraphBLAS/@GrB/find.m @@ -1,18 +1,18 @@ function [I, J, X] = find (G, k, search) -%FIND extract entries from a GraphBLAS matrix. -% [I, J, X] = find (G) extracts the nonzeros from a GraphBLAS matrix G. +%FIND extract entries from a matrix. +% [I, J, X] = find (G) extracts the nonzeros from a matrix G. % X has the same type as G ('double', 'single', 'int8', ...). % % Linear 1D indexing (I = find (S) for the MATLAB matrix S) is not yet % supported. % -% G may contain explicit zero entries, and by default these are excluded -% from the result. Use GrB.extracttuples (G) to return these explicit -% zero entries. +% A GraphBLAS matrix G may contain explicit zero entries, and by default +% these are excluded from the result. Use GrB.extracttuples (G) to return +% these explicit zero entries. % -% For a column vector, I = find (G) returns I as a list of the row -% indices of nonzeros in G. For a row vector, I = find (G) returns I as a -% list of the column indices of nonzeros in G. +% For a column vector, I = find (G) returns I as a list of the row indices +% of nonzeros in G. For a row vector, I = find (G) returns I as a list of +% the column indices of nonzeros in G. % % [...] = find (G, k, 'first') returns the first k nonozeros of G. % [...] = find (G, k, 'last') returns the last k nonozeros of G. @@ -21,6 +21,9 @@ % % See also sparse, GrB.build, GrB.extracttuples. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + % FUTURE: add linear indexing % FUTURE: find (G,k,'first') and find (G,k,'last') are slow, since as @@ -30,57 +33,66 @@ % of G, instead of using GrB_Matrix_extractTuples_*, which always extracts % the entire matrix. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. - -if (nargin > 1 && ~GrB.isbycol (G)) - % find (G, k) assumes the matrix is stored by column, so reformat G - % if it is stored by row. - G = GrB (G, 'by col') ; +if (isobject (G)) + G = G.opaque ; end -if (nnz (G) < GrB.entries (G)) - G = GrB.prune (G) ; +if (nargin > 1) + k = ceil (double (gb_get_scalar (k))) ; + if (k < 1) + error ('k must be positive') ; + end + if (~isequal (gbformat (G), 'by col')) + % find (G, k) assumes the matrix is stored by column, so reformat G + % if it is stored by row. + G = gbnew (G, 'by col') ; + end end +% prune explicit zeros +G = gbselect (G, 'nonzero') ; + +[m, n] = gbsize (G) ; + if (nargout == 3) - [I, J, X] = GrB.extracttuples (G) ; - if (isrow (G)) + [I, J, X] = gbextracttuples (G) ; + if (m == 1) I = I' ; J = J' ; X = X' ; end elseif (nargout == 2) - [I, J] = GrB.extracttuples (G) ; - if (isrow (G)) + [I, J] = gbextracttuples (G) ; + if (m == 1) I = I' ; J = J' ; end else - if (isrow (G)) - [~, I] = GrB.extracttuples (G) ; + if (m == 1) + % extract indices from a row vector + [~, I] = gbextracttuples (G) ; I = I' ; + elseif (n == 1) + % extract indices from a column vector + I = gbextracttuples (G) ; else - % FUTURE: this does not return the same thing - I = GrB.extracttuples (G) ; + % FUTURE: this does not return the same thing as I = find (G) + % in MATLAB. (need to add 1D linear indexing) + error ('Linear indexing not yet supported') ; + % I = gbextracttuples (G) ; end end if (nargin > 1) % find (G, k, ...): get the first or last k entries - if (nargin == 2) + if (nargin < 3) search = 'first' ; end - if (~isscalar (k)) - gb_error ('k must be a scalar') ; - end - k = ceil (double (k)) ; - if (k < 1) - gb_error ('k must be positive') ; - end n = length (I) ; - k = min (k, n) ; - if (isequal (search, 'first')) + if (k >= n) + % output already has all k first or last entries; + % nothing more to do + elseif (isequal (search, 'first')) % find (G, k, 'first'): get the first k entries I = I (1:k) ; if (nargout > 1) @@ -99,7 +111,7 @@ X = X (n-k+1:n) ; end else - gb_error ('invalid search option; must be ''first'' or ''last''') ; + error ('invalid search option; must be ''first'' or ''last''') ; end end diff --git a/GraphBLAS/@GrB/fix.m b/GraphBLAS/@GrB/fix.m index 8ebdba9e7c..dfda32f498 100644 --- a/GraphBLAS/@GrB/fix.m +++ b/GraphBLAS/@GrB/fix.m @@ -1,20 +1,17 @@ function C = fix (G) -%FIX Round towards entries in a GraphBLAS matrix to zero. -% C = fix (G) rounds the entries in the GraphBLAS matrix G to the -% nearest integers towards zero. +%FIX Round towards zero. +% C = fix (G) rounds the entries in the matrix G to the nearest integers +% towards zero. % -% See also ceil, floor, round. +% See also GrB/ceil, GrB/floor, GrB/round. -% FUTURE: this will be much faster as a mexFunction. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +Q = G.opaque ; -if (isfloat (G) && GrB.entries (G) > 0) - [m, n] = size (G) ; - desc.base = 'zero-based' ; - [i, j, x] = GrB.extracttuples (G, desc) ; - C = GrB.build (i, j, fix (x), m, n, desc) ; +if (gb_isfloat (gbtype (Q)) && gbnvals (Q) > 0) + C = GrB (gbapply ('trunc', Q)) ; else C = G ; end diff --git a/GraphBLAS/@GrB/flip.m b/GraphBLAS/@GrB/flip.m index 8e5c9b38dc..7eab0338d8 100644 --- a/GraphBLAS/@GrB/flip.m +++ b/GraphBLAS/@GrB/flip.m @@ -1,45 +1,52 @@ -function C = flip (G, dim) -%FLIP flip the order of elements -% C = flip (G) flips the order of elements in each column of G. That is, -% C = G (end:-1:1,:). C = flip (G, dim) specifies the dimension to flip, -% so that flip (G,1) and flip (G) are the same thing, and flip (G,2) flips -% the columns so that C = G (:,end:-1,1). +function C = flip (A, dim) +%FLIP flip the order of elements. +% C = flip (A) flips the order of elements in each column of A. That is, +% C = A (end:-1:1,:). C = flip (A, dim) specifies the dimension to flip, +% so that flip (A,1) and flip (A) are the same thing, and flip (A,2) flips +% the columns so that C = A (:,end:-1,1). % -% See also transpose. +% To use this function on a MATLAB matrix, use C = flip (A, GrB (dim)). +% +% See also GrB/transpose. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +a_is_object = isobject (A) ; +if (a_is_object) + G = A.opaque ; +else + G = A ; +end -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +[m, n] = gbsize (G) ; -if (nargin < 2) - if (isrow (G)) +if (nargin == 1) + if (m == 1) dim = 2 ; else dim = 1 ; end +else + dim = gb_get_scalar (dim) ; end -[m, n] = size (G) ; - -if (~isscalar (dim)) - gb_error ('dim must be a scalar') ; -end dim = floor (double (dim)) ; if (dim <= 0) - gb_error ('dim must be positive') ; + error ('dim must be positive') ; end if (dim == 1 && m ~= 1) - % C = G (m:-1:1, :) - I = { m, -1, 1 } ; - J = { } ; - C = GrB.extract (G, I, J) ; + % C = A (m:-1:1, :) + C = GrB (gbextract (G, {m,-1,1}, { })) ; elseif (dim == 2 && n ~= 1) - % C = G (:, n:-1:1) - I = { } ; - J = { n, -1, 1 } ; - C = GrB.extract (G, I, J) ; -else + % C = A (:, n:-1:1) + C = GrB (gbextract (G, { }, {n,-1,1})) ; +elseif (a_is_object) % nothing to do - C = G ; + C = A ; +else + % nothing to do except convert A to GrB + C = GrB (A) ; end diff --git a/GraphBLAS/@GrB/floor.m b/GraphBLAS/@GrB/floor.m index 5bc82766df..04be4df291 100644 --- a/GraphBLAS/@GrB/floor.m +++ b/GraphBLAS/@GrB/floor.m @@ -1,20 +1,17 @@ function C = floor (G) -%FLOOR round entries of a GraphBLAS matrix to the nearest ints to -inf. -% C = floor (G) rounds the entries in the GraphBLAS matrix G to the -% nearest integers towards -infinity. +%FLOOR round entries to nearest integers towards -infinity. +% C = floor (G) rounds the entries in the matrix G to the nearest integers +% towards -infinity. % -% See also ceil, round, fix. +% See also GrB/ceil, GrB/round, GrB/fix. -% FUTURE: this will be much faster as a mexFunction. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +Q = G.opaque ; -if (isfloat (G) && GrB.entries (G) > 0) - [m, n] = size (G) ; - desc.base = 'zero-based' ; - [i, j, x] = GrB.extracttuples (G, desc) ; - C = GrB.build (i, j, floor (x), m, n, desc) ; +if (gb_isfloat (gbtype (Q)) && gbnvals (Q) > 0) + C = GrB (gbapply ('floor', Q)) ; else C = G ; end diff --git a/GraphBLAS/@GrB/format.m b/GraphBLAS/@GrB/format.m index 773cf718f3..19355d3ae8 100644 --- a/GraphBLAS/@GrB/format.m +++ b/GraphBLAS/@GrB/format.m @@ -39,16 +39,16 @@ % all subsequent newly created matrices. % % All prior matrices created before GrB.format (f) are kept in their same -% format; this setting only applies to new matrices. Operations on matrices -% can be done with any mix of with different formats. The format only affects -% time and memory usage, not the results. +% format; this setting only applies to new matrices. Operations on +% matrices can be done with any mix of with different formats. The format +% only affects time and memory usage, not the results. % % The format of the output C of a GraphBLAS method is defined using the % following rules. The first rule that holds is used: % -% (1) GraphBLAS operations of the form Cout = GrB.method (Cin, ...) +% (1) GraphBLAS operations of the form C = GrB.method (Cin, ...) % that take a Cin input matrix, use the format of Cin as the format -% for Cout, if Cin is provided on input. +% for C, if Cin is provided on input. % (2) If the format is determined by the descriptor to the method, then % that determines the format of C. % (3) If C is a column vector then C is stored by column. @@ -77,23 +77,23 @@ % GrB.format (G) % GrB.format ('by row') ; % set the default format to 'by row' % G = GrB.build (1:3, 1:3, 1:3) -% GrB.format (G) % query the format of G (which is 'by row') +% GrB.format (G) % query the format of G, which is 'by row' % % See also GrB. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. if (nargin == 0) % f = GrB.format ; get the global format f = gbformat ; else - if (isa (arg, 'GrB')) - % f = GrB.format (G) ; get the format of the matrix G - f = gbformat (arg.opaque) ; - else - % f = GrB.format (f) ; set the global format for all future matrices - f = gbformat (arg) ; + if (isobject (arg)) + % f = GrB.format (G) ; get the format of the GraphBLAS matrix + arg = arg.opaque ; end + % f = GrB.format (A) ; get the format of the matrix A (MATLAB or GraphBLAS) + % f = GrB.format (f) ; set the global format for all matrices. + f = gbformat (arg) ; end diff --git a/GraphBLAS/@GrB/fprintf.m b/GraphBLAS/@GrB/fprintf.m index ea016557a2..ab28329dd0 100644 --- a/GraphBLAS/@GrB/fprintf.m +++ b/GraphBLAS/@GrB/fprintf.m @@ -1,13 +1,13 @@ function count = fprintf (varargin) %FPRINTF Write formatted data to a text file. -% The GraphBLAS fprintf function is identical to the built-in MATLAB function; -% this overloaded method simply typecasts any GraphBLAS matrices to MATLAB -% matrices first, and then calls the builtin fprintf. +% The GraphBLAS fprintf function is identical to the built-in MATLAB +% function; this overloaded method simply typecasts any GraphBLAS matrices +% to MATLAB matrices first, and then calls the builtin fprintf. % % See also fprintf, sprintf, GrB/sprintf. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. c = gb_printf_helper ('fprintf', varargin {:}) ; if (nargout > 0) diff --git a/GraphBLAS/@GrB/full.m b/GraphBLAS/@GrB/full.m index 130c9a8365..81fdb830a7 100644 --- a/GraphBLAS/@GrB/full.m +++ b/GraphBLAS/@GrB/full.m @@ -1,15 +1,17 @@ function C = full (A, type, identity) -%FULL convert a matrix into a GraphBLAS dense matrix. -% C = full (A, type, identity) converts the matrix A into a GraphBLAS -% dense matrix C of the given type, by inserting identity values. The -% type may be any GraphBLAS type: 'double', 'single', 'logical', 'int8' -% 'int16' 'int32' 'int64' 'uint8' 'uint16' 'uint32' 'uint64', or in the -% future, 'complex'. If not present, the type defaults to the same type -% as G, and the identity defaults to zero. A may be any matrix -% (GraphBLAS, MATLAB sparse or full). To use this method for a MATLAB -% matrix A, use a GraphBLAS identity value such as GrB(0), or use C = full -% (GrB (A)). Note that issparse (C) is true, since issparse (G) is true -% for any GraphBLAS matrix G. +%FULL convert a matrix into a GraphBLAS 'dense' matrix. +% C = full (A, type, identity) converts the matrix A into a GraphBLAS dense +% matrix C of the given type, by inserting identity values. The type may +% be any GraphBLAS type: 'double', 'single', 'single complex', 'double +% complex', 'logical', 'int8', 'int16', 'int32', 'int64', 'uint8', +% 'uint16', 'uint32', or 'uint64'. +% +% If not present, the type defaults to the same type as A, and the identity +% defaults to zero. A may be any matrix (GraphBLAS, MATLAB sparse or +% full). To use this method for a MATLAB matrix A, use a GraphBLAS +% identity value such as GrB(0), or use C = full (GrB (A)). Note that +% issparse (C) is true, since issparse (A) is true for any GraphBLAS matrix +% A. % % Examples: % @@ -17,27 +19,51 @@ % C = full (G) % add explicit zeros % C = full (G, 'double', inf) % add explicit inf's % -% A = speye (2) +% A = speye (2) % C = full (GrB (A), 'double', 0) % full GrB matrix C, from A % C = full (GrB (A)) % same matrix C % -% See also issparse, sparse, cast, GrB.type, GrB. +% See also GrB/issparse, sparse, cast, GrB.type, GrB, GrB.isfull. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -if (isa (A, 'GrB')) - A = A.opaque ; +A_is_GrB = isobject (A) ; +if (A_is_GrB) + % A is a GraphBLAS matrix + Q = A.opaque ; +else + % A is a MATLAB matrix + Q = A ; end + if (nargin < 2) - type = gbtype (A) ; -end -if (nargin < 3) - identity = 0 ; -end -if (isa (identity, 'GrB')) - identity = identity.opaque ; + type = gbtype (Q) ; + right_type = true ; +else + right_type = isequal (type, gbtype (Q)) ; end -C = GrB (gbfull (A, type, identity, struct ('kind', 'GrB'))) ; +if (gb_isfull (Q) && right_type) + + % nothing to do, A is already full and has the right type + if (A_is_GrB) + % A is already a GrB matrix, return it as-is + C = A ; + else + % convert A into a GrB matrix + C = GrB (A) ; + end + +else + + % convert A to a full GraphBLAS matrix + if (nargin < 3) + identity = 0 ; + elseif (isobject (identity)) + identity = identity.opaque ; + end + C = GrB (gbfull (Q, type, identity)) ; + +end diff --git a/GraphBLAS/@GrB/gamma.m b/GraphBLAS/@GrB/gamma.m new file mode 100644 index 0000000000..844173840e --- /dev/null +++ b/GraphBLAS/@GrB/gamma.m @@ -0,0 +1,21 @@ +function C = gamma (G) +%GAMMA gamma function. +% C = gamma (G) is the gamma function of each entry of G. +% Since gamma (0) = inf, the result is a full matrix. G must be real. +% +% See also GrB/gammaln. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; +if (contains (type, 'complex')) + error ('input must be real') ; +end +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gbapply ('gamma', gbfull (G, type))) ; + diff --git a/GraphBLAS/@GrB/gammaln.m b/GraphBLAS/@GrB/gammaln.m new file mode 100644 index 0000000000..73f307f1e7 --- /dev/null +++ b/GraphBLAS/@GrB/gammaln.m @@ -0,0 +1,22 @@ +function C = gammaln (G) +%GAMMALN logarithm of gamma function. +% C = gammaln (G) is the natural logarithm of the gamma function of each +% entry of G. Since gammaln (0) = inf, the result is a full matrix. +% G must be real. +% +% See also GrB/gammaln. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; +if (contains (type, 'complex')) + error ('input must be real') ; +end +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gbapply ('gammaln', gbfull (G, type))) ; + diff --git a/GraphBLAS/@GrB/ge.m b/GraphBLAS/@GrB/ge.m index 94ee088ebd..1b010b6f01 100644 --- a/GraphBLAS/@GrB/ge.m +++ b/GraphBLAS/@GrB/ge.m @@ -1,15 +1,12 @@ function C = ge (A, B) -%A >= B Greater than or equal to. +%A >= B greater than or equal to. % C = (A >= B) is an element-by-element comparison of A and B. One or % both may be scalars. Otherwise, A and B must have the same size. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% % See also GrB/lt, GrB/le, GrB/gt, GrB/ne, GrB/eq. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. C = le (B, A) ; diff --git a/GraphBLAS/@GrB/graph.m b/GraphBLAS/@GrB/graph.m index 084b7434a9..ed3236feba 100644 --- a/GraphBLAS/@GrB/graph.m +++ b/GraphBLAS/@GrB/graph.m @@ -1,19 +1,19 @@ function Graph = graph (G, varargin) %GRAPH convert a GraphBLAS matrix into a MATLAB undirected Graph. % Graph = graph (G) converts a GraphBLAS matrix G into an undirected MATLAB -% Graph. G is assumed to be symmetric; only tril (G) is used by default. G -% must be square. If G is logical, then no weights are added to the Graph. If -% G is single or double, these become the weights of the MATLAB Graph. If G is -% integer, the Graph is constructed with weights of type double. Optional -% string arguments can appear after G, in any order: +% Graph. G is assumed to be symmetric; only tril (G) is used by default. +% G must be square. If G is logical, then no weights are added to the +% Graph. If G is single or double, these become the weights of the MATLAB +% Graph. If G is integer, the Graph is constructed with weights of type +% double. % -% Graph = graph (G, ..., 'upper') uses only triu (G) to construct the Graph. -% Graph = graph (G, ..., 'lower') uses only tril (G) to construct the Graph. -% The default is 'lower'. +% Graph = graph (G, ..., 'upper') uses triu (G) to construct the Graph. +% Graph = graph (G, ..., 'lower') uses tril (G) to construct the Graph. +% The default is 'lower'. % -% Graph = graph (G, ..., 'omitselfloops') ignores the diagonal of G, and the -% resulting MATLAB Graph has no self-edges. The default is that self-edges -% are created from any diagonal entries of G. +% Graph = graph (G, ..., 'omitselfloops') ignores the diagonal of G, and +% the resulting MATLAB Graph has no self-edges. The default is that +% self-edges are created from any diagonal entries of G. % % Example: % @@ -23,13 +23,14 @@ % % See also graph, digraph, GrB/digraph. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -type = GrB.type (G) ; -[m, n] = size (G) ; +G = G.opaque ; + +[m, n, type] = gbsize (G) ; if (m ~= n) - gb_error ('G must be square') ; + error ('G must be square') ; end % get the string options @@ -43,7 +44,7 @@ case { 'omitselfloops' } omitself = true ; otherwise - gb_error ('unknown option') ; + error ('unknown option') ; end end @@ -51,29 +52,38 @@ if (omitself) % ignore diagonal entries of G if (isequal (side, 'upper')) - G = triu (G, 1) ; + G = gbselect ('triu', G, 1) ; elseif (isequal (side, 'lower')) - G = tril (G, -1) ; + G = gbselect ('tril', G, -1) ; end else % include diagonal entries of G if (isequal (side, 'upper')) - G = triu (G) ; + G = gbselect ('triu', G, 0) ; elseif (isequal (side, 'lower')) - G = tril (G) ; + G = gbselect ('tril', G, 0) ; end end % construct the graph -if (isequal (type, 'logical')) - Graph = graph (logical (G), side) ; -elseif (isequal (type, 'double')) - Graph = graph (double (G), side) ; -elseif (isequal (type, 'single')) - [i, j, x] = GrB.extracttuples (G) ; - Graph = graph (i, j, x, n) ; -else - % all other types (int* and uint*) must be cast to double - Graph = graph (double (GrB (G, 'double')), side) ; +switch (type) + + case { 'single' } + + % The MATLAB graph(...) function can accept x as single, but not + % from a MATLAB sparse matrix. So extract the tuples of G first. + [i, j, x] = gbextracttuples (G) ; + Graph = graph (i, j, x, n) ; + + case { 'logical' } + + % The MATLAB digraph(...) function allows for sparse logical + % adjacency matrices (no edge weights are created). + Graph = graph (gbsparse (G, 'logical'), side) ; + + otherwise + + % typecast to double + Graph = graph (gbsparse (G, 'double'), side) ; end diff --git a/GraphBLAS/@GrB/gt.m b/GraphBLAS/@GrB/gt.m index 4b8d81df53..b2ea1ed826 100644 --- a/GraphBLAS/@GrB/gt.m +++ b/GraphBLAS/@GrB/gt.m @@ -1,15 +1,15 @@ function C = gt (A, B) -%A > B Greater than. +%A > B greater than. % C = (A > B) is an element-by-element comparison of A and B. One or % both may be scalars. Otherwise, A and B must have the same size. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% % See also GrB/lt, GrB/le, GrB/ge, GrB/ne, GrB/eq. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% FUTURE: gt(A,B) for two matrices A and B is slower than it could be. +% See comments in gb_union_op. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. C = lt (B, A) ; diff --git a/GraphBLAS/@GrB/horzcat.m b/GraphBLAS/@GrB/horzcat.m index e3a42816c2..f7850ea62c 100644 --- a/GraphBLAS/@GrB/horzcat.m +++ b/GraphBLAS/@GrB/horzcat.m @@ -1,38 +1,42 @@ function C = horzcat (varargin) -%HORZCAT Horizontal concatenation. +%HORZCAT horizontal concatenation. % [A B] or [A,B] is the horizontal concatenation of A and B. -% A and B may be GraphBLAS or MATLAB matrices, in any combination. % Multiple matrices may be concatenated, as [A, B, C, ...]. +% If the matrices have different types, the type is determined +% according to the results in GrB.optype. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% -% See also vertcat, GrB/vertcat. +% See also GrB/vertcat, GrB.optype. % FUTURE: this will be much faster when it is a mexFunction. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. % determine the size of each matrix and the size of the result nmatrices = length (varargin) ; nvals = zeros (1, nmatrices) ; ncols = zeros (1, nmatrices) ; A = varargin {1} ; -[m, n] = size (A) ; -nvals (1) = GrB.entries (A) ; +if (isobject (A)) + A = A.opaque ; +end +[m, n, type] = gbsize (A) ; +nvals (1) = gbnvals (A) ; ncols (1) = n ; -type = GrB.type (A) ; clear A for k = 2:nmatrices - B = varargin {k} ; - [m2, n] = size (B) ; + A = varargin {k} ; + if (isobject (A)) + A = A.opaque ; + end + [m2, n2, type2] = gbsize (A) ; if (m ~= m2) - gb_error ('Dimensions of arrays being concatenated are not consistent'); + error ('Dimensions of arrays not consistent') ; end - nvals (k) = GrB.entries (B) ; - ncols (k) = n ; - clear B ; + nvals (k) = gbnvals (A) ; + ncols (k) = n2 ; + type = gboptype (type, type2) ; + clear A ; end ncols = [0 cumsum(ncols)] ; nvals = [0 cumsum(nvals)] ; @@ -47,15 +51,19 @@ % fill the I,J,X arrays desc.base = 'zero-based' ; for k = 1:nmatrices - [i, j, x] = GrB.extracttuples (varargin {k}, desc) ; + A = varargin {k} ; + if (isobject (A)) + A = A.opaque ; + end + [i, j, x] = gbextracttuples (A, desc) ; noffset = int64 (ncols (k)) ; - koffset = nvals (k) ; - kvals = GrB.entries (varargin {k}) ; - I ((koffset+1):(koffset+kvals)) = i ; - J ((koffset+1):(koffset+kvals)) = j + noffset ; - X ((koffset+1):(koffset+kvals)) = x ; + k1 = nvals (k) + 1 ; + k2 = nvals (k+1) ; + I (k1:k2) = i ; + J (k1:k2) = j + noffset ; + X (k1:k2) = x ; end % build the output matrix -C = GrB.build (I, J, X, m, n, desc) ; +C = GrB (gbbuild (I, J, X, m, n, desc)) ; diff --git a/GraphBLAS/@GrB/hypot.m b/GraphBLAS/@GrB/hypot.m new file mode 100644 index 0000000000..2c4d3b4658 --- /dev/null +++ b/GraphBLAS/@GrB/hypot.m @@ -0,0 +1,41 @@ +function C = hypot (A, B) +%HYPOT robust computation of the square root of sum of squares. +% C = hypot (A,B) computes sqrt (abs (A).^2 + abs (B).^2) accurately. +% If A and B are matrices, the pattern of C is the set union of A and B. +% If one of A or B is a nonzero scalar, the scalar is expanded into a +% dense matrix the size of the other matrix, and the result is a full +% matrix. +% +% See also GrB/abs, GrB/norm, GrB/sqrt, GrB/plus, GrB.eadd. + +% FUTURE: hypot(A,B) for two matrices A and B is slower than it could be. +% See comments in gb_union_op. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +atype = gbtype (A) ; +btype = gbtype (B) ; + +if (contains (atype, 'complex')) + A = gbapply ('abs', A) ; +elseif (~gb_isfloat (atype)) + A = gbnew (A, 'double') ; +end + +if (contains (btype, 'complex')) + B = gbapply ('abs', B) ; +elseif (~gb_isfloat (btype)) + B = gbnew (B, 'double') ; +end + +C = GrB (gbapply ('abs', gb_eadd (A, 'hypot', B))) ; + diff --git a/GraphBLAS/@GrB/imag.m b/GraphBLAS/@GrB/imag.m new file mode 100644 index 0000000000..1f1009b8ce --- /dev/null +++ b/GraphBLAS/@GrB/imag.m @@ -0,0 +1,20 @@ +function C = imag (G) +%IMAG complex imaginary part. +% C = imag (G) returns the imaginary part of G. +% +% See also GrB/conj, GrB/real. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +[m, n, type] = gbsize (G) ; + +if (contains (type, 'complex')) + % C = imag (G) where G is complex + C = GrB (gbapply ('cimag', G)) ; +else + % G is real, so C = zeros (m,n) + C = GrB (gbnew (m, n, type)) ; +end + diff --git a/GraphBLAS/@GrB/incidence.m b/GraphBLAS/@GrB/incidence.m index 1e5bb52661..84bc6c124a 100644 --- a/GraphBLAS/@GrB/incidence.m +++ b/GraphBLAS/@GrB/incidence.m @@ -1,16 +1,15 @@ function C = incidence (A, varargin) -%GRB.INCIDENCE Graph incidence matrix. +%GRB.INCIDENCE graph incidence matrix. % C = GrB.incidence (A) is the graph incidence matrix of the square % matrix A. C is GraphBLAS matrix of size n-by-e, if A is n-by-n with e -% entries (not including diagonal entries). The jth column of has 2 +% entries (not including diagonal entries). The jth column of C has 2 % entries: C(s,j) = -1 and C(t,j) = 1, where A(s,t) is an entry A. -% Diagonal entries in A are ignored. Optional string arguments can -% appear after A: +% Diagonal entries in A are ignored. % % C = GrB.incidence (A, ..., 'directed') constructs a matrix C of size % n-by-e where e = GrB.entries (GrB.offdiag (A)). Any entry in the % upper or lower trianglar part of A results in a unique column of -% C. The diagonal is ignored. This is the default. +% C. The diagonal is ignored. This is the default. % % C = GrB.incidence (A, ..., 'unsymmetric') is the same as 'directed'. % @@ -25,9 +24,10 @@ % C = GrB.incidence (A, ..., 'upper') is the same as 'undirected', % except that only entries in triu (A,1) are used. % -% C = GrB.incidence (A, ..., type) construct C with the type 'double', +% C = GrB.incidence (A, ..., type) constructs C with the type 'double', % 'single', 'int8', 'int16', 'int32', or 'int64'. The default is -% 'double'. +% 'double'. The type cannot be 'logical' or 'uint*' since C +% must contain -1's. % % Examples: % @@ -36,12 +36,16 @@ % % See also graph/incidence, digraph/incidence. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -[m, n] = size (A) ; +if (isobject (A)) + A = A.opaque ; +end + +[m, n] = gbsize (A) ; if (m ~= n) - gb_error ('A must be square') ; + error ('A must be square') ; end % get the string options @@ -55,30 +59,43 @@ kind = arg ; case { 'double', 'single', 'int8', 'int16', 'int32', 'int64' } type = arg ; + case { 'uint8', 'uint16', 'uint32', 'uint64', 'logical' } + error ('type must be signed') ; otherwise - gb_error ('unknown option') ; + error ('unknown option') ; end end -if (isequal (kind, 'directed') || isequal (kind, 'unsymmetric')) - % create the incidence matrix of a directed graph, using all of A; - % except that diagonal entries are ignored. - A = GrB.offdiag (A) ; -elseif (isequal (kind, 'upper')) - % create the incidence matrix of an undirected graph, using only entries - % in the strictly upper triangular part of A. - A = triu (A, 1) ; -else - % create the incidence matrix of an undirected graph, using only entries - % in the strictly lower triangular part of A. - A = tril (A, -1) ; +switch (kind) + + case { 'directed', 'unsymmetric' } + + % create the incidence matrix of a directed graph, using all of A; + % except that diagonal entries are ignored. + A = gbselect ('offdiag', A, 0) ; + + case { 'upper' } + + % create the incidence matrix of an undirected graph, using only + % entries in the strictly upper triangular part of A. + A = gbselect ('triu', A, 1) ; + + otherwise % 'undirected', 'symmetric', or 'lower' + + % create the incidence matrix of an undirected graph, using only + % entries in the strictly lower triangular part of A. + A = gbselect ('tril', A, -1) ; + end % build the incidence matrix desc.base = 'zero-based' ; -[i, j] = GrB.extracttuples (A, desc) ; -e = length (i) ; -k = (int64 (0) : int64 (e-1))' ; -x = ones (e, 1, type) ; -C = GrB.build ([i ; j], [k ; k], [-x ; x], n, e, desc) ; +[I, J] = gbextracttuples (A, desc) ; +e = length (I) ; +I = [I ; J] ; +J = (int64 (0) : int64 (e-1))' ; +J = [J ; J] ; +X = ones (e, 1, type) ; +X = [-X ; X] ; +C = GrB (gbbuild (I, J, X, n, e, desc)) ; diff --git a/GraphBLAS/@GrB/init.m b/GraphBLAS/@GrB/init.m index 970a71f73b..09e5e1dcef 100644 --- a/GraphBLAS/@GrB/init.m +++ b/GraphBLAS/@GrB/init.m @@ -1,19 +1,15 @@ function init %GRB.INIT initialize SuiteSparse:GraphBLAS. % -% Usage: -% % GrB.init % % GrB.init initializes all SuiteSparse:GraphBLAS settings to their -% defaults. In prior versions (v3.1.2), its use was required before -% calling any SuiteSparse:GraphBLAS function in MATLAB. Its use is now -% optional in this version of SuiteSparse:GraphBLAS. +% defaults. Its use is optional. % -% See also: GrB.clear, GrB.finalize, startup. +% See also GrB.clear, GrB.finalize, startup. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. gbsetup ; diff --git a/GraphBLAS/@GrB/int16.m b/GraphBLAS/@GrB/int16.m index 4598126310..2ee9286d68 100644 --- a/GraphBLAS/@GrB/int16.m +++ b/GraphBLAS/@GrB/int16.m @@ -7,11 +7,13 @@ % To typecast the matrix G to a GraphBLAS sparse int16 matrix instead, % use C = GrB (G, 'int16'). % -% See also GrB, double, complex, single, logical, int8, int32, int64, -% uint8, uint16, uint32, and uint64. +% See also GrB, GrB/double, GrB/complex, GrB/single, GrB/logical, GrB/int8, +% GrB/int32, GrB/int64, GrB/uint8, GrB/uint16, GrB/uint32, GrB/uint64. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = gbfull (G.opaque, 'int16') ; +G = G.opaque ; +desc.kind = 'full' ; +C = gbfull (G, 'int16', int16 (0), desc) ; diff --git a/GraphBLAS/@GrB/int32.m b/GraphBLAS/@GrB/int32.m index 9cabb72741..0165406d19 100644 --- a/GraphBLAS/@GrB/int32.m +++ b/GraphBLAS/@GrB/int32.m @@ -7,11 +7,13 @@ % To typecast the matrix G to a GraphBLAS sparse int32 matrix instead, % use C = GrB (G, 'int32'). % -% See also GrB, double, complex, single, logical, int8, int16, int32, -% int64, uint8, uint16, uint32, and uint64. +% See also GrB, GrB/double, GrB/complex, GrB/single, GrB/logical, GrB/int8, +% GrB/int16, GrB/int64, GrB/uint8, GrB/uint16, GrB/uint32, GrB/uint64. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = gbfull (G.opaque, 'int32') ; +G = G.opaque ; +desc.kind = 'full' ; +C = gbfull (G, 'int32', int32 (0), desc) ; diff --git a/GraphBLAS/@GrB/int64.m b/GraphBLAS/@GrB/int64.m index 9e46e32aa2..f92334f540 100644 --- a/GraphBLAS/@GrB/int64.m +++ b/GraphBLAS/@GrB/int64.m @@ -7,11 +7,13 @@ % To typecast the matrix G to a GraphBLAS sparse int64 matrix instead, % use C = GrB (G, 'int64'). % -% See also GrB, double, complex, single, logical, int8, int16, int32, -% uint8, uint16, uint32, and uint64. +% See also GrB, GrB/double, GrB/complex, GrB/single, GrB/logical, GrB/int8, +% GrB/int16, GrB/int32, GrB/uint8, GrB/uint16, GrB/uint32, GrB/uint64. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = gbfull (G.opaque, 'int64') ; +G = G.opaque ; +desc.kind = 'full' ; +C = gbfull (G, 'int64', int64 (0), desc) ; diff --git a/GraphBLAS/@GrB/int8.m b/GraphBLAS/@GrB/int8.m index adb2169406..cce3b6363b 100644 --- a/GraphBLAS/@GrB/int8.m +++ b/GraphBLAS/@GrB/int8.m @@ -7,11 +7,14 @@ % To typecast the matrix G to a GraphBLAS sparse int8 matrix instead, use % C = GrB (G, 'int8'). % -% See also GrB, double, complex, single, logical, int8, int16, int32, -% int64, uint8, uint16, uint32, and uint64. +% See also GrB, GrB/double, GrB/complex, GrB/single, GrB/logical, +% GrB/int16, GrB/int32, GrB/int64, GrB/uint8, GrB/uint16, GrB/uint32, +% GrB/uint64. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = gbfull (G.opaque, 'int8') ; +G = G.opaque ; +desc.kind = 'full' ; +C = gbfull (G, 'int8', int8 (0), desc) ; diff --git a/GraphBLAS/@GrB/isa.m b/GraphBLAS/@GrB/isa.m index dbd2f2a905..a360a742d3 100644 --- a/GraphBLAS/@GrB/isa.m +++ b/GraphBLAS/@GrB/isa.m @@ -1,38 +1,41 @@ -function s = isa (G, classname) -%ISA Determine if a GraphBLAS matrix is of specific class. -% -% For any GraphBLAS matrix G, isa (G, 'GrB'), isa (G, 'numeric'), and isa -% (G, 'object') are always true. +function s = isa (G, type) +%ISA Determine if a GraphBLAS matrix is of specific type. +% For any GraphBLAS matrix G, isa (G, 'GrB') and isa (G, 'numeric') are +% always true, even if G is logical, since many semirings are defined for +% that type. % % isa (G, 'float') is the same as isfloat (G), and is true if the GrB -% matrix G has type 'double', 'single', or 'complex'. +% matrix G has type 'double', 'single', 'single complex', or 'double +% complex'. % % isa (G, 'integer') is the same as isinteger (G), and is true if the GrB % matrix G has type 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', % 'uint32', or 'uint64'. % -% isa (G, classname) is true if the classname matches the type of G. +% isa (G, type) is true if the type string matches the type of G. +% +% Otherwise, all other cases are handled with builtin ('isa',G,type). % -% See also GrB.type, isnumeric, islogical, ischar, iscell, isstruct, -% isfloat, isinteger, isobject, isjava, issparse, isreal, class. +% See also class, GrB.type, GrB/isnumeric, GrB/islogical, GrB/isfloat, +% GrB/isinteger, isobject, GrB/issparse, GrB/isreal. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -if (isequal (classname, 'GrB') || isequal (classname, 'numeric')) +if (isequal (type, 'GrB') || isequal (type, 'numeric')) % all GraphBLAS matrices are numeric, and have class name 'GrB' s = true ; -elseif (isequal (classname, 'float')) +elseif (isequal (type, 'float')) % GraphBLAS double, single, and complex matrices are 'float' s = isfloat (G) ; -elseif (isequal (classname, 'integer')) +elseif (isequal (type, 'integer')) % GraphBLAS int* and uint* matrices are 'integer' s = isinteger (G) ; -elseif (isequal (GrB.type (G), classname)) - % specific cases, such as isa (G, 'double') +elseif (isequal (GrB.type (G), type)) + % specific cases, such as isa (G, 'double'), isa (G, 'int8'), etc s = true ; else % catch-all for cases not handled above - s = builtin ('isa', G, classname) ; + s = builtin ('isa', G, type) ; end diff --git a/GraphBLAS/@GrB/isbanded.m b/GraphBLAS/@GrB/isbanded.m index 6d40350dbc..b52f85aee7 100644 --- a/GraphBLAS/@GrB/isbanded.m +++ b/GraphBLAS/@GrB/isbanded.m @@ -1,15 +1,21 @@ -function s = isbanded (G, lo, hi) -%ISBANDED True if G is a banded GraphBLAS matrix. -% isbanded (G, lo, hi) is true if the bandwidth of the GraphBLAS matrix G -% is between lo and hi. +function s = isbanded (A, lo, hi) +%ISBANDED true if A is a banded matrix. +% isbanded (A, lo, hi) is true if the bandwidth of A is between lo and hi. % -% See also istril, istriu, bandwidth. +% See also GrB/istril, GrB/istriu, GrB/bandwidth. -% FUTURE: this will be much faster when 'bandwidth' is a mexFunction. +% FUTURE: this will be much faster when 'gb_bandwidth' is a mexFunction. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com See GraphBLAS/Doc/License.txt. -[Glo, Ghi] = bandwidth (G) ; -s = (Glo <= lo) & (Ghi <= hi) ; +if (isobject (A)) + A = A.opaque ; +end + +lo = gb_get_scalar (lo) ; +hi = gb_get_scalar (hi) ; + +[alo, ahi] = gb_bandwidth (A) ; +s = (alo <= lo) & (ahi <= hi) ; diff --git a/GraphBLAS/@GrB/isbycol.m b/GraphBLAS/@GrB/isbycol.m index 4a9d49e6d3..e62cd9da00 100644 --- a/GraphBLAS/@GrB/isbycol.m +++ b/GraphBLAS/@GrB/isbycol.m @@ -1,10 +1,18 @@ -function s = isbycol (X) -%GRB.ISBYCOL True if X is stored by column, false if by column. -% s = GrB.isbycol (X) is true if X is stored by column, false if by row. -% X may be a GraphBLAS matrix or MATLAB matrix (sparse or full). MATLAB +function s = isbycol (A) +%GRB.ISBYCOL true if A is stored by column, false if by column. +% s = GrB.isbycol (A) is true if A is stored by column, false if by row. +% A may be a GraphBLAS matrix or MATLAB matrix (sparse or full). MATLAB % matrices are always stored by column. % % See also GrB.isbyrow, GrB.format. -s = isequal (GrB.format (X), 'by col') ; +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; + s = isequal (gbformat (A), 'by col') ; +else + s = true ; +end diff --git a/GraphBLAS/@GrB/isbyrow.m b/GraphBLAS/@GrB/isbyrow.m index 4c0a112cf9..03bead6e1e 100644 --- a/GraphBLAS/@GrB/isbyrow.m +++ b/GraphBLAS/@GrB/isbyrow.m @@ -1,10 +1,17 @@ -function s = isbyrow (X) -%GRB.ISBYROW True if X is stored by row, false if by column. -% s = GrB.isbyrow (X) is true if X is stored by row, false if by column. -% X may be a GraphBLAS matrix or MATLAB matrix (sparse or full). MATLAB +function s = isbyrow (A) +%GRB.ISBYROW true if A is stored by row, false if by column. +% s = GrB.isbyrow (A) is true if A is stored by row, false if by column. +% A may be a GraphBLAS matrix or MATLAB matrix (sparse or full). MATLAB % matrices are always stored by column. % % See also GrB.isbycol, GrB.format. -s = isequal (GrB.format (X), 'by row') ; +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. +if (isobject (A)) + A = A.opaque ; + s = isequal (gbformat (A), 'by row') ; +else + s = false ; +end diff --git a/GraphBLAS/@GrB/isdiag.m b/GraphBLAS/@GrB/isdiag.m index 12203843d9..e2392f73b9 100644 --- a/GraphBLAS/@GrB/isdiag.m +++ b/GraphBLAS/@GrB/isdiag.m @@ -1,13 +1,19 @@ function s = isdiag (G) -%ISDIAG True if the GraphBLAS matrix G is a diagonal matrix. +%ISDIAG true if G is a diagonal matrix. % isdiag (G) is true if G is a diagonal matrix, and false otherwise. % % See also GrB/isbanded. -% FUTURE: this will be much faster when 'bandwidth' is a mexFunction. +% FUTURE: this will faster when 'gb_bandwidth' is a mexFunction. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -s = isbanded (G, 0, 0) ; +G = G.opaque ; + +% using gb_bandwidth instead: +% [lo, hi] = gb_bandwidth (G) ; +% s = (lo == 0) & (hi == 0) ; + +s = (gbnvals (gbselect ('diag', G, 0)) == gbnvals (G)) ; diff --git a/GraphBLAS/@GrB/isempty.m b/GraphBLAS/@GrB/isempty.m index 8e844628a0..296cb7a933 100644 --- a/GraphBLAS/@GrB/isempty.m +++ b/GraphBLAS/@GrB/isempty.m @@ -1,11 +1,11 @@ function s = isempty (G) -%ISEMPTY true for empty GraphBLAS matrix. +%ISEMPTY true for an empty matrix. % isempty (G) is true if any dimension of G is zero. % -% See also size. +% See also GrB/size. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. [m, n] = size (G) ; s = (m == 0) | (n == 0) ; diff --git a/GraphBLAS/@GrB/isequal.m b/GraphBLAS/@GrB/isequal.m index dfae9156a9..a7cc1be1c9 100644 --- a/GraphBLAS/@GrB/isequal.m +++ b/GraphBLAS/@GrB/isequal.m @@ -7,7 +7,7 @@ % % If A is a GraphBLAS matrix with an explicit entry equal to zero, but in % B that entry is not present, then isequal (A,B) returns false. To drop -% them, use isequal (GrB.prune(A), GrB.prune(B)) ; +% them, use isequal (GrB.prune(A), GrB.prune(B)). % % The input matrices may be either GraphBLAS and/or MATLAB matrices, in % any combination. A and B do not have to be the same class. For @@ -15,10 +15,13 @@ % % See also isequal, GrB/eq, isequaln. -if (isa (A, 'GrB')) +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) A = A.opaque ; end -if (isa (B, 'GrB')) +if (isobject (B)) B = B.opaque ; end diff --git a/GraphBLAS/@GrB/isfinite.m b/GraphBLAS/@GrB/isfinite.m index 4a91c50183..56b715de15 100644 --- a/GraphBLAS/@GrB/isfinite.m +++ b/GraphBLAS/@GrB/isfinite.m @@ -1,20 +1,18 @@ function C = isfinite (G) -%ISFINITE True for finite elements. -% C = isfinite (G) returns a GraphBLAS logical matrix where C(i,j) = true -% if G(i,j) is finite. +%ISFINITE true for finite elements. +% C = isfinite (G) is a logical matrix where C(i,j) = true +% if G(i,j) is finite. C is a full matrix. % -% See also isnan, isinf. +% See also GrB/isnan, GrB/isinf. -% FUTURE: this will be much faster as a mexFunction. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +G = G.opaque ; +[m, n, type] = gbsize (G) ; -[m, n] = size (G) ; -if (isfloat (G) && m > 0 && n > 0) - desc.base = 'zero-based' ; - [i, j, x] = GrB.extracttuples (full (G), desc) ; - C = GrB.build (i, j, isfinite (x), m, n, desc) ; +if (gb_isfloat (type) && m > 0 && n > 0) + C = GrB (gbapply ('isfinite', gbfull (G))) ; else % C is all true C = GrB (true (m, n)) ; diff --git a/GraphBLAS/@GrB/isfloat.m b/GraphBLAS/@GrB/isfloat.m index f6d6f7741d..6d6c4d3651 100644 --- a/GraphBLAS/@GrB/isfloat.m +++ b/GraphBLAS/@GrB/isfloat.m @@ -1,13 +1,14 @@ function s = isfloat (G) -%ISFLOAT true for floating-point GraphBLAS matrices. -% isfloat (G) is true if the GraphBLAS matrix G has a type of 'double', -% 'single', or 'complex'. +%ISFLOAT true for floating-point matrices. +% isfloat (G) is true if the matrix G has a type of 'double', +% 'single', 'single complex', or 'double complex'. % -% See also isnumeric, isreal, isinteger, islogical, GrB.type, isa, GrB. +% See also GrB/isnumeric, GrB/isreal, GrB/isinteger, GrB/islogical, +% GrB.type, GrB/isa, GrB. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -t = gbtype (G.opaque) ; -s = isequal (t, 'double') || isequal (t, 'single') || isequal (t, 'complex') ; +G = G.opaque ; +s = gb_isfloat (gbtype (G)) ; diff --git a/GraphBLAS/@GrB/isfull.m b/GraphBLAS/@GrB/isfull.m index 4212e32076..fd373adcd2 100644 --- a/GraphBLAS/@GrB/isfull.m +++ b/GraphBLAS/@GrB/isfull.m @@ -1,14 +1,24 @@ function s = isfull (A) %GRB.ISFULL determine if all entries are present. -% For a GraphBLAS matrix, or a MATLAB sparse matrix, GrB.isfull (A) is true if -% numel (A) == nnz (A). A can be a GraphBLAS matrix, or a MATLAB sparse or -% full matrix. GrB.isfull (A) is always true if A is a MATLAB full matrix. +% For a GraphBLAS matrix, or a MATLAB sparse matrix, GrB.isfull (A) is true +% if numel (A) == nnz (A). A can be a GraphBLAS matrix, or a MATLAB sparse +% or full matrix. GrB.isfull (A) is always true if A is a MATLAB full +% matrix. % -% See also issparse. +% See also GrB/issparse, GrB/full. -if (isa (A, 'GrB') || issparse (A)) - s = (numel (A) == GrB.entries (A)) ; +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + % GraphBLAS matrix + A = A.opaque ; + s = gb_isfull (A) ; +elseif (issparse (A)) + % MATLAB sparse matrix + s = (numel (A) == nnz (A)) ; else + % MATLAB full matrix, string, struct, etc s = true ; end diff --git a/GraphBLAS/@GrB/ishermitian.m b/GraphBLAS/@GrB/ishermitian.m index e16b217de8..2218b1cbfb 100644 --- a/GraphBLAS/@GrB/ishermitian.m +++ b/GraphBLAS/@GrB/ishermitian.m @@ -1,35 +1,19 @@ function s = ishermitian (G, option) -%ISHERMITIAN Determine if a GraphBLAS matrix is Hermitian, or real symmetric. +%ISHERMITIAN Determine if a matrix is Hermitian or real symmetric. % ishermitian (G) is true if G equals G' and false otherwise. % ishermitian (G, 'skew') is true if G equals -G' and false otherwise. % ishermitian (G, 'nonskew') is the same as ishermitian (G). % -% See also issymmetric. +% See also GrB/issymmetric. -% FUTURE: this can be much faster. See CHOLMOD/MATLAB/spsym. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +G = G.opaque ; -[m, n] = size (G) ; -if (m ~= n) - s = false ; -else - if (nargin < 2) - option = 'nonskew' ; - end - if (islogical (G)) - G = GrB (G, 'double') ; - end - if (isequal (option, 'skew')) - s = (norm (G + G', 1) == 0) ; - else - s = (GrB.normdiff (G, G', 1) == 0) ; - end - if (s) - % also check the pattern; G might have explicit zeros - S = spones (G, 'logical') ; - s = isequal (S, S') ; - end +if (nargin < 2) + option = 'nonskew' ; end +s = gb_issymmetric (G, option, true) ; + diff --git a/GraphBLAS/@GrB/isinf.m b/GraphBLAS/@GrB/isinf.m index c865ada1e6..8ddf2ee3e1 100644 --- a/GraphBLAS/@GrB/isinf.m +++ b/GraphBLAS/@GrB/isinf.m @@ -1,20 +1,18 @@ function C = isinf (G) -%ISINF True for infinite elements. -% C = isinf (G) returns a GraphBLAS logical matrix where C(i,j) = true +%ISINF true for infinite elements. +% C = isinf (G) returns a logical matrix C where C(i,j) = true % if G(i,j) is infinite. % -% See also isnan, isfinite. +% See also GrB/isnan, GrB/isfinite. -% FUTURE: this will be much faster as a mexFunction. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +G = G.opaque ; +[m, n, type] = gbsize (G) ; -[m, n] = size (G) ; -if (isfloat (G) && GrB.entries (G) > 0) - desc.base = 'zero-based' ; - [i, j, x] = GrB.extracttuples (G, desc) ; - C = GrB.build (i, j, isinf (x), m, n, desc) ; +if (gb_isfloat (type) && gbnvals (G) > 0) + C = GrB (gbapply ('isinf', G)) ; else % C is all false C = GrB (m, n, 'logical') ; diff --git a/GraphBLAS/@GrB/isinteger.m b/GraphBLAS/@GrB/isinteger.m index 9e1011757b..87a4ccd357 100644 --- a/GraphBLAS/@GrB/isinteger.m +++ b/GraphBLAS/@GrB/isinteger.m @@ -1,16 +1,14 @@ function s = isinteger (G) -%ISINTEGER true for integer GraphBLAS matrices. -% isinteger (G) is true if the GraphBLAS matrix G has an integer type +%ISINTEGER true for integer matrices. +% isinteger (G) is true if the matrix G has an integer type % (int8, int16, int32, int64, uint8, uint16, uint32, or uint64). % -% See also isnumeric, isfloat, isreal, islogical, GrB.type, isa, GrB. +% See also GrB/isnumeric, GrB/isfloat, GrB/isreal, GrB/islogical, +% GrB.type, GrB/isa, GrB. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -t = gbtype (G.opaque) ; -s = isequal (t, 'int8' ) || isequal (t, 'int16' ) || ... - isequal (t, 'int32' ) || isequal (t, 'int64' ) || ... - isequal (t, 'uint8' ) || isequal (t, 'uint16') || ... - isequal (t, 'uint32') || isequal (t, 'uint64') ; +G = G.opaque ; +s = contains (gbtype (G), 'int') ; diff --git a/GraphBLAS/@GrB/islogical.m b/GraphBLAS/@GrB/islogical.m index 9937cce8d0..4ff0fd3033 100644 --- a/GraphBLAS/@GrB/islogical.m +++ b/GraphBLAS/@GrB/islogical.m @@ -1,11 +1,13 @@ function s = islogical (G) -%ISLOGICAL true for logical GraphBLAS matrices. -% islogical (G) is true if the GraphBLAS matrix G has the logical type. +%ISLOGICAL true for logical matrices. +% islogical (G) is true if the matrix G has the logical type. % -% See also isnumeric, isfloat, isreal, isinteger, GrB.type, isa, GrB. +% See also GrB/isnumeric, GrB/isfloat, GrB/isreal, GrB/isinteger, +% GrB.type, GrB/isa, GrB. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -s = isequal (gbtype (G.opaque), 'logical') ; +G = G.opaque ; +s = isequal (gbtype (G), 'logical') ; diff --git a/GraphBLAS/@GrB/ismatrix.m b/GraphBLAS/@GrB/ismatrix.m index ea70169655..af9dae7942 100644 --- a/GraphBLAS/@GrB/ismatrix.m +++ b/GraphBLAS/@GrB/ismatrix.m @@ -2,10 +2,11 @@ %ISMATRIX always true for any GraphBLAS matrix. % ismatrix (G) is always true for any GraphBLAS matrix G. % -% See also issparse, isvector, isscalar, sparse, full, isa, GrB. +% See also GrB/issparse, GrB/isvector, GrB/isscalar, GrB/full, GrB/isa, +% GrB. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. s = true ; diff --git a/GraphBLAS/@GrB/isnan.m b/GraphBLAS/@GrB/isnan.m index 8ea6cd176e..ee9ea68a41 100644 --- a/GraphBLAS/@GrB/isnan.m +++ b/GraphBLAS/@GrB/isnan.m @@ -1,20 +1,17 @@ function C = isnan (G) -%ISNAN True for NaN elements. -% C = isnan (G) for a GraphBLAS matrix G returns a GraphBLAS logical -% matrix with C(i,j)=true if G(i,j) is NaN. +%ISNAN true for NaN elements. +% C = isnan (G) is a logical C matrix with C(i,j)=true if G(i,j) is NaN. % -% See also isinf, isfinite. +% See also GrB/isinf, GrB/isfinite. -% FUTURE: this will be much faster as a mexFunction. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +G = G.opaque ; +[m, n, type] = gbsize (G) ; -[m, n] = size (G) ; -if (isfloat (G) && GrB.entries (G) > 0) - desc.base = 'zero-based' ; - [i, j, x] = GrB.extracttuples (G, desc) ; - C = GrB.build (i, j, isnan (x), m, n, desc) ; +if (gb_isfloat (type) && gbnvals (G) > 0) + C = GrB (gbapply ('isnan', G)) ; else % C is all false C = GrB (m, n, 'logical') ; diff --git a/GraphBLAS/@GrB/isnumeric.m b/GraphBLAS/@GrB/isnumeric.m index fb892b3ad4..486efd3a98 100644 --- a/GraphBLAS/@GrB/isnumeric.m +++ b/GraphBLAS/@GrB/isnumeric.m @@ -4,10 +4,11 @@ % logical matrices, since those matrices can be operated on in any % semiring, just like any other GraphBLAS matrix. % -% See also isfloat, isreal, isinteger, islogical, GrB.type, isa, GrB. +% See also GrB/isfloat, GrB/isreal, GrB/isinteger, GrB/islogical, +% GrB.type, GrB/isa, GrB. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. s = true ; diff --git a/GraphBLAS/@GrB/isreal.m b/GraphBLAS/@GrB/isreal.m index 2d0b7f8c31..1a75c4e560 100644 --- a/GraphBLAS/@GrB/isreal.m +++ b/GraphBLAS/@GrB/isreal.m @@ -1,13 +1,14 @@ function s = isreal (G) -%ISREAL true for real GraphBLAS matrices. +%ISREAL true for real matrices. % isreal (G) is true for a GraphBLAS matrix G, unless it has a type of -% 'complex'. Note that complex matrices are not yet supported, so -% currently isreal (G) is true for all GraphBLAS matrices. +% 'single complex' or 'double complex'. % -% See also isnumeric, isfloat, isinteger, islogical, GrB.type, isa, GrB. +% See also GrB/isnumeric, GrB/isfloat, GrB/isinteger, GrB/islogical, +% GrB.type, GrB/isa, GrB. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -s = ~isequal (gbtype (G.opaque), 'complex') ; +G = G.opaque ; +s = ~contains (gbtype (G), 'complex') ; diff --git a/GraphBLAS/@GrB/isscalar.m b/GraphBLAS/@GrB/isscalar.m index c58ca75aaf..17bd314d5a 100644 --- a/GraphBLAS/@GrB/isscalar.m +++ b/GraphBLAS/@GrB/isscalar.m @@ -1,12 +1,12 @@ function s = isscalar (G) -%ISSCALAR determine if the GraphBLAS matrix is a scalar. +%ISSCALAR determine if a matrix is a scalar. % isscalar (G) is true for an m-by-n GraphBLAS matrix if m and n are 1. % -% See also issparse, ismatrix, isvector, sparse, full, isa, GrB, size. +% See also GrB/issparse, GrB/ismatrix, GrB/isvector, GrB/issparse, +% GrB/isfull, GrB/isa, GrB, GrB/size. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. - -[m, n] = size (G) ; -s = (m == 1) && (n == 1) ; +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. +G = G.opaque ; +s = gb_isscalar (G) ; diff --git a/GraphBLAS/@GrB/issigned.m b/GraphBLAS/@GrB/issigned.m index 5a25f575bb..a0bbb62f52 100644 --- a/GraphBLAS/@GrB/issigned.m +++ b/GraphBLAS/@GrB/issigned.m @@ -1,14 +1,25 @@ -function s = issigned (type) +function s = issigned (arg) %GRB.ISSIGNED Determine if a type is signed or unsigned. % s = GrB.issigned (type) returns true if type is the string 'double', -% 'single', 'int8', 'int16', 'int32', or 'int64'. +% 'single', 'single complex', 'double complex', 'int8', 'int16', 'int32', +% or 'int64'. % -% See also isinteger, isreal, isnumeric, isfloat. +% s = GrB.issigned (A), where A is a matrix, is the same as +% s = GrB.issigned (GrB.type (A)). +% +% See also GrB/isinteger, GrB/isreal, GrB/isnumeric, GrB/isfloat, GrB.type. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +if (ischar (arg)) + type = arg ; +elseif (isobject (arg)) + arg = arg.opaque ; + type = gbtype (arg) ; +else + type = gbtype (arg) ; +end -s = isequal (type, 'double') || isequal (type, 'single') || ... - isequal (type, 'int8') || isequal (type, 'int16') || ... - isequal (type, 'int32') || isequal (type, 'int64') ; +s = gb_issigned (type) ; diff --git a/GraphBLAS/@GrB/issparse.m b/GraphBLAS/@GrB/issparse.m index 449231b0a4..3dbb67d37f 100644 --- a/GraphBLAS/@GrB/issparse.m +++ b/GraphBLAS/@GrB/issparse.m @@ -1,11 +1,17 @@ function s = issparse (G) %#ok %ISSPARSE always true for any GraphBLAS matrix. -% issparse (G) is always true for any GraphBLAS matrix G. +% A GraphBLAS matrix always keeps track of its pattern, even if all entries +% are present. Thus, issparse (G) is always true for any GraphBLAS matrix +% G; even issparse (full (G)) is true. % -% See also ismatrix, isvector, isscalar, sparse, full, isa, GrB. +% To check if all entries are present in G, use GrB.isfull (G). The +% expression GrB.isfull (full (G)) is always true. GrB.isfull (G) is false +% if GrB.entries (G) < prod (size (G)). +% +% See also GrB/ismatrix, GrB/isvector, GrB/isscalar, GrB/isfull, GrB. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. s = true ; diff --git a/GraphBLAS/@GrB/issymmetric.m b/GraphBLAS/@GrB/issymmetric.m index d6d69d50e3..6b785c4b10 100644 --- a/GraphBLAS/@GrB/issymmetric.m +++ b/GraphBLAS/@GrB/issymmetric.m @@ -4,32 +4,16 @@ % issymmetric (G, 'skew') is true if G equals -G.' and false otherwise. % issymmetric (G, 'nonskew') is the same as issymmetric (G). % -% See also ishermitian. +% See also GrB/ishermitian. -% FUTURE: this will be much faster. See CHOLMOD/MATLAB/spsym. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +G = G.opaque ; -[m, n] = size (G) ; -if (m ~= n) - s = false ; -else - if (nargin < 2) - option = 'nonskew' ; - end - if (islogical (G)) - G = GrB (G, 'double') ; - end - if (isequal (option, 'skew')) - s = (norm (G + G.', 1) == 0) ; - else - s = (GrB.normdiff (G, G.', 1) == 0) ; - end - if (s) - % also check the pattern; G might have explicit zeros - S = spones (G, 'logical') ; - s = isequal (S, S') ; - end +if (nargin < 2) + option = 'nonskew' ; end +s = gb_issymmetric (G, option, false) ; + diff --git a/GraphBLAS/@GrB/istril.m b/GraphBLAS/@GrB/istril.m index 4bfaf80d91..0865310a37 100644 --- a/GraphBLAS/@GrB/istril.m +++ b/GraphBLAS/@GrB/istril.m @@ -1,17 +1,18 @@ function s = istril (G) -%ISTRIL Determine if a matrix is lower triangular. -% istril (G) is true if all entries in the GraphBLAS matrix G are on or -% below the diagonal. A GraphBLAS matrix G may have explicit zeros. If -% these appear in the upper triangular part of G, then istril (G) is -% false, but istril (double (G)) can be true since double (G) drops those -% entries. +%ISTRIL determine if a matrix is lower triangular. +% istril (G) is true if all entries in G are on or below the diagonal. A +% GraphBLAS matrix G may have explicit zeros. If these appear in the upper +% triangular part of G, then istril (G) is false, but istril (double (G)) +% can be true since double (G) drops those entries. % % See also GrB/istriu, GrB/isbanded. -% FUTURE: this will be much faster when written as a mexFunction. +% FUTURE: this will be much faster when written as a mexFunction +% that doesn't rely on gbselect. Use a gb_bandwith mexFunction. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -s = (GrB.entries (triu (G, 1)) == 0) ; +G = G.opaque ; +s = (gbnvals (gbselect ('triu', G, 1)) == 0) ; diff --git a/GraphBLAS/@GrB/istriu.m b/GraphBLAS/@GrB/istriu.m index 079913c68d..5f9c0e721e 100644 --- a/GraphBLAS/@GrB/istriu.m +++ b/GraphBLAS/@GrB/istriu.m @@ -1,17 +1,18 @@ function s = istriu (G) -%ISTRIU Determine if a matrix is upper triangular. -% istriu (G) is true if all entries in the GraphBLAS matrix G are on or -% above the diagonal. A GraphBLAS matrix G may have explicit zeros. If -% these appear in the lower triangular part of G, then istriu (G) is -% false, but istriu (double (G)) can be true since double (G) drops those -% entries. +%ISTRIU determine if a matrix is upper triangular. +% istriu (G) is true if all entries in G are on or above the diagonal. A +% GraphBLAS matrix G may have explicit zeros. If these appear in the lower +% triangular part of G, then istriu (G) is false, but istriu (double (G)) +% can be true since double (G) drops those entries. % % See also GrB/istriu, GrB/isbanded. -% FUTURE: this will be much faster when written as a mexFunction. +% FUTURE: this will be much faster when written as a mexFunction +% that doesn't rely on gbselect. Use a gb_bandwith mexFunction. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -s = (GrB.entries (tril (G, -1)) == 0) ; +G = G.opaque ; +s = (gbnvals (gbselect ('tril', G, -1)) == 0) ; diff --git a/GraphBLAS/@GrB/isvector.m b/GraphBLAS/@GrB/isvector.m index 02b6e6a8f9..17b11d72b9 100644 --- a/GraphBLAS/@GrB/isvector.m +++ b/GraphBLAS/@GrB/isvector.m @@ -1,12 +1,13 @@ function s = isvector (G) -%ISVECTOR determine if the GraphBLAS matrix is a row or column vector. -% isvector (G) is true for an m-by-n GraphBLAS matrix if m or n is 1. +%ISVECTOR determine if a matrix is a row or column vector. +% isvector (G) is true for an m-by-n matrix G if m or n is 1. % -% See also issparse, ismatrix, isscalar, sparse, full, isa, GrB, size. +% See also GrB/issparse, GrB/ismatrix, GrB/isscalar, GrB/issparse, +% GrB/isfull, GrB/isa, GrB, GrB/size. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -[m, n] = size (G) ; -s = (m == 1) || (n == 1) ; +G = G.opaque ; +s = gb_isvector (G) ; diff --git a/GraphBLAS/@GrB/kron.m b/GraphBLAS/@GrB/kron.m index 92321662f5..a07e49d674 100644 --- a/GraphBLAS/@GrB/kron.m +++ b/GraphBLAS/@GrB/kron.m @@ -1,13 +1,19 @@ function C = kron (A, B) %KRON sparse Kronecker product. % C = kron (A,B) is the sparse Kronecker tensor product of A and B. -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. % % See also GrB.kronecker. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB.kronecker (A, '*', B) ; +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +C = GrB (gbkronecker (A, '*', B)) ; diff --git a/GraphBLAS/@GrB/kronecker.m b/GraphBLAS/@GrB/kronecker.m index 872d716372..792204c8d9 100644 --- a/GraphBLAS/@GrB/kronecker.m +++ b/GraphBLAS/@GrB/kronecker.m @@ -1,33 +1,61 @@ -function Cout = kronecker (varargin) +function C = kronecker (arg1, arg2, arg3, arg4, arg5, arg6, arg7) %GRB.KRONECKER sparse Kronecker product. % -% Usage: +% C = GrB.kronecker (op, A, B, desc) +% C = GrB.kronecker (Cin, accum, op, A, B, desc) +% C = GrB.kronecker (Cin, M, op, A, B, desc) +% C = GrB.kronecker (Cin, M, accum, op, A, B, desc) % -% Cout = GrB.kronecker (op, A, B, desc) -% Cout = GrB.kronecker (Cin, accum, op, A, B, desc) -% Cout = GrB.kronecker (Cin, M, op, A, B, desc) -% Cout = GrB.kronecker (Cin, M, accum, op, A, B, desc) -% -% GrB.kronecker computes the Kronecker product, T=kron(A,B), using the given -% binary operator op, in place of the conventional '*' operator for the -% MATLAB built-in kron. See also C = kron (A,B), which uses the default -% semiring operators if A and/or B are GrB matrices. -% -% All input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. Cout is returned as a GraphBLAS matrix, by default; -% see 'help GrB/descriptorinfo' for more options. +% GrB.kronecker computes the Kronecker product, T=kron(A,B), using the +% given binary operator op, in place of the conventional '*' operator for +% the MATLAB built-in kron. See also C = kron (A,B), which uses the +% default semiring operators if A and/or B are GrB matrices. % % T is then accumulated into C via C<#M,replace> = accum (C,T). % % See also kron, GrB/kron. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (arg1)) + arg1 = arg1.opaque ; +end + +if (isobject (arg2)) + arg2 = arg2.opaque ; +end + +if (isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +if (nargin > 4 && isobject (arg5)) + arg5 = arg5.opaque ; +end + +if (nargin > 5 && isobject (arg6)) + arg6 = arg6.opaque ; +end + +switch (nargin) + case 3 + [C, k] = gbkronecker (arg1, arg2, arg3) ; + case 4 + [C, k] = gbkronecker (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbkronecker (arg1, arg2, arg3, arg4, arg5) ; + case 6 + [C, k] = gbkronecker (arg1, arg2, arg3, arg4, arg5, arg6) ; + case 7 + [C, k] = gbkronecker (arg1, arg2, arg3, arg4, arg5, arg6, arg7) ; +end -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - Cout = GrB (gbkronecker (args {:})) ; -else - Cout = gbkronecker (args {:}) ; +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/ktruss.m b/GraphBLAS/@GrB/ktruss.m index ba3a99d9c1..e14a907c3c 100644 --- a/GraphBLAS/@GrB/ktruss.m +++ b/GraphBLAS/@GrB/ktruss.m @@ -1,23 +1,24 @@ function C = ktruss (A, k, check) %GRB.KTRUSS find the k-truss of a matrix. -% C = GrB.ktruss (A, k) finds the k-truss of a matrix A. spones (A) must be -% symmetric with no diagonal entries. Only the pattern of A is considered. -% The ktruss C is a graph consisting of a subset of the edges of A. Each edge -% in C is part of at least k-2 triangles in A, where a triangle is a set of 3 -% unique nodes that form a clique. The pattern of C is the k-truss, and the -% edge weights of C are the support of each edge. That is, C(i,j) = nt if the -% edge (i,j) is part of nt triangles in C. All edges in C have a support of at -% least nt >= k-2. The total number of triangles in C is sum(C,'all')/6. C is -% returned as a symmetric matrix with a zero-free diagonal. If k is not -% present, it defaults to 3. +% C = GrB.ktruss (A, k) finds the k-truss of a matrix A. spones (A) must +% be symmetric with no diagonal entries. Only the pattern of A is +% considered. The ktruss C is a graph consisting of a subset of the edges +% of A. Each edge in C is part of at least k-2 triangles in A, where a +% triangle is a set of 3 unique nodes that form a clique. The pattern of C +% is the k-truss, and the edge weights of C are the support of each edge. +% That is, C(i,j) = nt if the edge (i,j) is part of nt triangles in C. All +% edges in C have a support of at least nt >= k-2. The total number of +% triangles in C is sum(C,'all')/6. C is returned as a symmetric matrix +% with a zero-free diagonal. If k is not present, it defaults to 3. % % To compute a sequence of k-trusses, a k1-truss can be efficiently used to % construct another k2-truss with k2 > k1. % % To check the input A to make sure it has a symmetric pattern and has a % zero-free diagonal, use C = GrB.ktruss (A, k, 'check'). This check is -% optional since it adds extra time. Results are undefined if 'check' is not -% specified and A has an unsymmetric pattern or entries on the diagonal. +% optional since it adds extra time. Results are undefined if 'check' is +% not specified and A has an unsymmetric pattern or entries on the +% diagonal. % % The output C is symmetric with a zero-free diagonal. % @@ -30,19 +31,21 @@ % ntriangles = sum (C3, 'all') / 6 % C4a = GrB.ktruss (A, 4) ; % C4b = GrB.ktruss (C3, 4) ; % this is faster -% assert (isequal (C4a, C4b)) ; +% isequal (C4a, C4b) % % See also GrB.tricount. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +% NOTE: this is a high-level algorithm that uses GrB objects. % check inputs if (nargin < 2) k = 3 ; end if (k < 3) - gb_error ('k-truss defined only for k >= 3') ; + error ('k-truss defined only for k >= 3') ; end if (nargin < 3) @@ -53,7 +56,7 @@ [m, n] = size (A) ; if (m ~= n) - gb_error ('A must be square') ; + error ('A must be square') ; end int_type = 'int64' ; @@ -66,10 +69,10 @@ if (check) % Do the costly checks. These are optional. if (~issymmetric (C)) - gb_error ('A must have a symmetric pattern') ; + error ('A must have a symmetric pattern') ; end if (nnz (diag (C) > 0)) - gb_error ('A must have a zero-free diagonal') ; + error ('A must have a zero-free diagonal') ; end end diff --git a/GraphBLAS/@GrB/laplacian.m b/GraphBLAS/@GrB/laplacian.m index 30f53b3e19..e08a7e7705 100644 --- a/GraphBLAS/@GrB/laplacian.m +++ b/GraphBLAS/@GrB/laplacian.m @@ -1,18 +1,23 @@ function L = laplacian (A, type, check) -%GRB.LAPLACIAN Graph Laplacian matrix -% L = laplacian (A) is the graph Laplacian of the matrix A. spones(A) must be -% symmetric with no diagonal entries. The diagonal of L is the degree of the -% nodes. That is, L(j,j) = sum (spones (A (:,j))). For off-diagonal entries, -% L(i,j) = L(j,i) = -1 if the edge (i,j) exists in A. +%GRB.LAPLACIAN Laplacian matrix +% L = laplacian (A) is the graph Laplacian of the matrix A. spones(A) +% must be symmetric. The diagonal of A is ignored. The diagonal of L is +% the degree of the nodes. That is, L(j,j) = sum (spones (A (:,j))), +% assuming A has no diagonal entries.. For off-diagonal entries, L(i,j) = +% L(j,i) = -1 if the edge (i,j) exists in A. % -% The type of L defaults to double. With a second argument, the type of L can -% be specified, as L = laplacian (A,type); type may be 'double', 'single', -% 'int8', 'int16', 'int32', or 'int64'. Be aware that integer overflow may -% occur with the smaller integer types. +% The type of L defaults to double. With a second argument, the type of L +% can be specified, as L = laplacian (A,type); type may be 'double', +% 'single', 'int8', 'int16', 'int32', 'int64', 'single complex', or +% 'double complex'. Be aware that integer overflow may occur with the +% smaller integer types, if the degree of any nodes exceeds the largest +% integer value. % -% To check the input matrix, use GrB.laplacian (A, 'double', 'check') ; +% spones(A) must be symmetric on input, but this condition is not checked +% by default. If it is not symmetric, the results are undefined. To +% check this condition, use GrB.laplacian (A, 'double', 'check') ; % -% L is returned as symmetric matrix. +% L is returned as symmetric GraphBLAS matrix. % % Example: % @@ -21,40 +26,45 @@ % % See also graph/laplacian. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -if (nargin < 2) - type = 'double' ; +if (isobject (A)) + A = A.opaque ; end -if (nargin < 3) - check = false ; -else - check = isequal (check, 'check') ; + +[m, n] = gbsize (A) ; +if (m ~= n) + error ('A must be square and symmetric') ; end -if (~GrB.issigned (type)) +% get the type +if (nargin < 2) + type = 'double' ; +elseif (~gb_issigned (type)) % type must be signed - gb_error ('invalid type') ; + error ('type cannot be logical or unsigned integer') ; end -A = GrB.apply (['1.' type], A) ; +% S = spones (A) +S = gbapply (['1.' type], A) ; -if (check) - if (~issymmetric (A)) - gb_error ('A must be symmetric') ; - end - if (GrB.entries (diag (A)) > 0) - gb_error ('A must have no diagonal entries') ; +% check the input matrix, if requested +if (nargin > 2 && isequal (check, 'check')) + % make sure spones (S) is symmetric + if (~gb_issymmetric (S, 'nonskew', false)) + error ('spones(A) must be symmetric') ; end end -if (GrB.isbycol (A)) - D = GrB.vreduce ('+', A, struct ('in0', 'transpose')) ; -else - D = GrB.vreduce ('+', A) ; +% D = diagonal matrix with d(i,i) = row/column degree of node i +D = gb_diag (gbdegree (S, true), 0) ; +if (~isequal (type, gbtype (D))) + % gbdegree returns its result as int64; typecast to desired type + D = gbnew (D, type) ; end % construct the Laplacian -L = - GrB.offdiag (A) + diag (D) ; +% L = D-S +L = GrB (gbeadd (D, '+', gbapply ('-', S))) ; diff --git a/GraphBLAS/@GrB/ldivide.m b/GraphBLAS/@GrB/ldivide.m index 3a4c43758a..05aa52e97b 100644 --- a/GraphBLAS/@GrB/ldivide.m +++ b/GraphBLAS/@GrB/ldivide.m @@ -4,8 +4,8 @@ % % See also GrB/rdivide. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. C = rdivide (B, A) ; diff --git a/GraphBLAS/@GrB/le.m b/GraphBLAS/@GrB/le.m index 38d933cabf..17b6ccce07 100644 --- a/GraphBLAS/@GrB/le.m +++ b/GraphBLAS/@GrB/le.m @@ -1,11 +1,8 @@ function C = le (A, B) -%A <= B Less than or equal to. +%A <= B less than or equal to. % C = (A <= B) is an element-by-element comparison of A and B. One or % both may be scalars. Otherwise, A and B must have the same size. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% % See also GrB/lt, GrB/gt, GrB/ge, GrB/ne, GrB/eq. % The pattern of C depends on the type of inputs: @@ -13,56 +10,61 @@ % A scalar, B matrix: C is full if A<=0, otherwise C is a subset of B. % B scalar, A matrix: C is full if B>=0, otherwise C is a subset of A. % A matrix, B matrix: C is full. -% Zeroes are then dropped from C after it is computed. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +[am, an, atype] = gbsize (A) ; +[bm, bn, btype] = gbsize (B) ; +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; +ctype = gboptype (atype, btype) ; -if (isscalar (A)) - if (isscalar (B)) +if (a_is_scalar) + if (b_is_scalar) % both A and B are scalars. C is full. - C = gb_dense_comparator (A, '<=', B) ; + C = GrB (gbemult (gbfull (A, ctype), '<=', gbfull (B, ctype))) ; else % A is a scalar, B is a matrix - if (gb_get_scalar (A) <= 0) + if (gb_scalar (A) <= 0) % since a <= 0, entries not present in B result in a true % value, so the result is dense. Expand A to a dense matrix. - [m, n] = size (B) ; - % A (1:m,1:n) = A and cast to the type of B - A = GrB.subassign (GrB (m, n, GrB.type (B)), A) ; - if (~GrB.isfull (B)) - B = full (B) ; - end - C = GrB.emult (A, '<=', B) ; + A = gb_scalar_to_full (bm, bn, ctype, A) ; + B = gbfull (B, ctype) ; + C = GrB (gbemult (A, '<=', B)) ; else % since a > 0, entries not present in B result in a false % value, so the result is a sparse subset of B. select all % entries in B >= a, then convert to true. - C = GrB.apply ('1.logical', GrB.select (B, '>=', A)) ; + C = GrB (gbapply ('1.logical', gbselect (B, '>=', A))) ; end end else - if (isscalar (B)) + if (b_is_scalar) % A is a matrix, B is a scalar - if (gb_get_scalar (B) >= 0) + if (gb_scalar (B) >= 0) % since b >= 0, entries not present in A result in a true % value, so the result is dense. Expand B to a dense matrix. - [m, n] = size (A) ; - % B (1:m,1:n) = B and cast to the type of A - B = GrB.subassign (GrB (m, n, GrB.type (A)), B) ; - if (~GrB.isfull (A)) - A = full (A) ; - end - C = GrB.emult (A, '<=', B) ; + B = gb_scalar_to_full (am, an, ctype, B) ; + A = gbfull (A, ctype) ; + C = GrB (gbemult (A, '<=', B)) ; else % since b < 0, entries not present in A result in a false % value, so the result is a sparse subset of A. select all % entries in A <= b, then convert to true. - C = GrB.apply ('1.logical', GrB.select (A, '<=', B)) ; + C = GrB (gbapply ('1.logical', gbselect (A, '<=', B))) ; end else % both A and B are matrices. C is full. - C = gb_dense_comparator (A, '<=', B) ; + C = GrB (gbemult (gbfull (A, ctype), '<=', gbfull (B, ctype))) ; end end diff --git a/GraphBLAS/@GrB/length.m b/GraphBLAS/@GrB/length.m index dcce043cb2..2c8aeedf92 100644 --- a/GraphBLAS/@GrB/length.m +++ b/GraphBLAS/@GrB/length.m @@ -1,16 +1,17 @@ function n = length (G) -%LENGTH the length of a GraphBLAS vector. +%LENGTH the length of a vector. % length (G) is the length of the vector G. For matrices, it is % max (size (G)) if G is non-empty, or zero if G has any zero dimension. % If any dimension of G exceeds flintmax, the result is returned as int64 % to avoid integer overflow. % -% See also size, numel. +% See also GrB/size, GrB/numel. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -[m, n] = size (G) ; +G = G.opaque ; +[m, n] = gbsize (G) ; if (m == 0 || n == 0) n = 0 ; diff --git a/GraphBLAS/@GrB/log.m b/GraphBLAS/@GrB/log.m new file mode 100644 index 0000000000..83aaf9276a --- /dev/null +++ b/GraphBLAS/@GrB/log.m @@ -0,0 +1,14 @@ +function C = log (G) +%LOG natural logarithm. +% C = log (G) is the natural logarithm of each entry of G. +% Since log (0) is nonzero, the result is a full matrix. +% If any entry in G is negative, the result is complex. +% +% See also GrB/log1p, GrB/log2, GrB/log10, GrB/exp. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +C = GrB (gb_to_real_if_imag_zero (gb_trig ('log', gbfull (G)))) ; + diff --git a/GraphBLAS/@GrB/log10.m b/GraphBLAS/@GrB/log10.m new file mode 100644 index 0000000000..ba35adb20c --- /dev/null +++ b/GraphBLAS/@GrB/log10.m @@ -0,0 +1,14 @@ +function C = log10 (G) +%LOG10 base-10 logarithm. +% C = log10 (G) is the base-10 logarithm of each entry of G. +% Since log10 (0) is nonzero, the result is a full matrix. +% If any entry in G is negative, the result is complex. +% +% See also GrB/log, GrB/log1p, GrB/log2, GrB/exp. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +C = GrB (gb_to_real_if_imag_zero (gb_trig ('log10', gbfull (G)))) ; + diff --git a/GraphBLAS/@GrB/log1p.m b/GraphBLAS/@GrB/log1p.m new file mode 100644 index 0000000000..de34f689d1 --- /dev/null +++ b/GraphBLAS/@GrB/log1p.m @@ -0,0 +1,13 @@ +function C = log1p (G) +%LOG1P natural logarithm. +% C = log1p (G) is log(1+x) for each entry x of G. +% If any entry in G is < -1, the result is complex. +% +% See also GrB/log, GrB/log2, GrB/log10, GrB/exp. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +C = GrB (gb_trig ('log1p', G)) ; + diff --git a/GraphBLAS/@GrB/log2.m b/GraphBLAS/@GrB/log2.m new file mode 100644 index 0000000000..87bbd43206 --- /dev/null +++ b/GraphBLAS/@GrB/log2.m @@ -0,0 +1,37 @@ +function [F, E] = log2 (G) +%LOG2 base-2 logarithm. +% C = log2 (G) is the base-2 logarithm of each entry of a GraphBLAS matrix +% G. Since log2 (0) is nonzero, the result is a full matrix. If any entry +% in G is negative, the result is complex. +% +% [F,E] = log2 (G) returns F and E so that G = F.*(2.^E), where entries in +% abs (F) are either in the range [0.5,1), or zero if the entry in G is +% zero. F and E are both sparse, with the same pattern as G. If G is +% complex, [F,E] = log2 (real (G)). +% +% See also GrB/pow2, GrB/log, GrB/log1p, GrB/log10, GrB/exp. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; + +if (nargout == 1) + % C = log2 (G) + F = GrB (gb_to_real_if_imag_zero (gb_trig ('log2', gbfull (G)))) ; +else + % [F,E] = log2 (G) + type = gbtype (G) ; + switch (type) + case { 'logical', 'int8', 'int16', 'int32', 'int64', ... + 'uint8', 'uint16', 'uint32', 'uint64', 'double complex' } + type = 'double' ; + case { 'single complex' } + type = 'single' ; + case { 'single', 'double' } + % type remains the same + end + F = GrB (gbapply (['frexpx.' type], G)) ; + E = GrB (gbapply (['frexpe.' type], G)) ; +end + diff --git a/GraphBLAS/@GrB/logical.m b/GraphBLAS/@GrB/logical.m index 665f09287f..19e736e36a 100644 --- a/GraphBLAS/@GrB/logical.m +++ b/GraphBLAS/@GrB/logical.m @@ -1,16 +1,18 @@ function C = logical (G) -%LOGICAL typecast a GraphBLAS sparse matrix to MATLAB sparse logical matrix. -% C = logical (G) typecasts the GraphBLAS matrix G to into a MATLAB -% sparse logical matrix. +%LOGICAL typecast a GraphBLAS matrix to MATLAB sparse logical matrix. +% C = logical (G) typecasts the GraphBLAS matrix G to into a MATLAB sparse +% logical matrix. % % To typecast the matrix G to a GraphBLAS sparse logical matrix instead, % use C = GrB (G, 'logical'). % -% See also cast, GrB, double, complex, single, int8, int16, int32, int64, -% uint8, uint16, uint32, and uint64. +% See also cast, GrB, GrB/double, GrB/complex, GrB/single, GrB/int8, +% GrB/int16, GrB/int32, GrB/int64, GrB/uint8, GrB/uint16, GrB/uint32, +% GrB/uint64. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = gbsparse (G.opaque, 'logical') ; +G = G.opaque ; +C = gbsparse (G, 'logical') ; diff --git a/GraphBLAS/@GrB/lt.m b/GraphBLAS/@GrB/lt.m index 480dd6f58c..116d10f24b 100644 --- a/GraphBLAS/@GrB/lt.m +++ b/GraphBLAS/@GrB/lt.m @@ -1,68 +1,80 @@ function C = lt (A, B) -%A < B Less than. +%A < B less than. % C = (A < B) is an element-by-element comparison of A and B. One or % both may be scalars. Otherwise, A and B must have the same size. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% % See also GrB/le, GrB/gt, GrB/ge, GrB/ne, GrB/eq. +% FUTURE: lt(A,B) for two matrices A and B is slower than it could be. +% See comments in gb_union_op. + % The pattern of C depends on the type of inputs: % A scalar, B scalar: C is scalar. % A scalar, B matrix: C is full if A<0, otherwise C is a subset of B. % B scalar, A matrix: C is full if B>0, otherwise C is a subset of A. % A matrix, B matrix: C has the pattern of the set union, A+B. -% Zeroes are then dropped from C after it is computed. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +[am, an, atype] = gbsize (A) ; +[bm, bn, btype] = gbsize (B) ; +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; +ctype = gboptype (atype, btype) ; -if (isscalar (A)) - if (isscalar (B)) +if (a_is_scalar) + if (b_is_scalar) % both A and B are scalars - C = GrB.emult (A, '<', B) ; + C = GrB (gb_union_op ('<', A, B)) ; else % A is a scalar, B is a matrix - if (gb_get_scalar (A) < 0) - % since a < 0, entries not present in B result in a true - % value, so the result is dense. Expand A to a dense matrix. - [m, n] = size (B) ; - % A (1:m,1:n) = A and cast to the type of B - A = GrB.subassign (GrB (m, n, GrB.type (B)), A) ; - if (~GrB.isfull (B)) - B = full (B) ; + if (gb_scalar (A) < 0) + if (~gb_issigned (btype)) + % a < 0, and B has an unsigned type. C is all true. + C = GrB (gb_scalar_to_full (bm, bn, 'logical', true)) ; + else + % since a < 0, entries not present in B result in a true + % value, so the result is dense. Expand A to dense. + A = gb_scalar_to_full (bm, bn, ctype, A) ; + C = GrB (gbemult (A, '<', gbfull (B, ctype))) ; end - C = GrB.emult (A, '<', B) ; else % since a >= 0, entries not present in B result in a false % value, so the result is a sparse subset of B. select all % entries in B > a, then convert to true. - C = GrB.apply ('1.logical', GrB.select (B, '>', A)) ; + C = GrB (gbapply ('1.logical', gbselect (B, '>', A))) ; end end else - if (isscalar (B)) + if (b_is_scalar) % A is a matrix, B is a scalar - if (gb_get_scalar (B) > 0) + b = gb_scalar (B) ; + if (b < 0 && ~gb_issigned (atype)) + % b is negative, and A has an unsigned type. C is all false. + C = GrB (gbnew (am, an, 'logical')) ; + elseif (b > 0) % since b > 0, entries not present in A result in a true % value, so the result is dense. Expand B to a dense matrix. - [m, n] = size (A) ; - % B (1:m,1:n) = B and cast to the type of A - B = GrB.subassign (GrB (m, n, GrB.type (A)), B) ; - if (~GrB.isfull (A)) - A = full (A) ; - end - C = GrB.emult (A, '<', B) ; + B = gb_scalar_to_full (am, an, ctype, B) ; + C = GrB (gbemult (gbfull (A, ctype), '<', B)) ; else % since b <= 0, entries not present in A result in a false % value, so the result is a sparse subset of A. Select all % entries in A < b, then convert to true. - C = GrB.apply ('1.logical', GrB.select (A, '<', B)) ; + C = GrB (gbapply ('1.logical', gbselect (A, '<', B))) ; end else % both A and B are matrices. C is the set union of A and B. - C = gb_sparse_comparator (A, '<', B) ; + C = GrB (gb_union_op ('<', A, B)) ; end end diff --git a/GraphBLAS/@GrB/max.m b/GraphBLAS/@GrB/max.m index 9e82edbca5..722bc41e3b 100644 --- a/GraphBLAS/@GrB/max.m +++ b/GraphBLAS/@GrB/max.m @@ -1,125 +1,56 @@ -function C = max (varargin) -%MAX Maximum elements of a GraphBLAS or MATLAB matrix. -% C = max (G) is the largest entry in the vector G. If G is a matrix, -% C is a row vector with C(j) = max (G (:,j)). +function C = max (A, B, option) +%MAX Maximum elements of a matrix. +% C = max (A) is the largest entry in the vector A. If A is a matrix, +% C is a row vector with C(j) = max (A (:,j)). % % C = max (A,B) is an array of the element-wise maximum of two matrices % A and B, which either have the same size, or one can be a scalar. -% Either A and/or B can be GraphBLAS or MATLAB matrices. % -% C = max (G, [ ], 'all') is a scalar, with the largest entry in G. -% C = max (G, [ ], 1) is a row vector with C(j) = max (G (:,j)) -% C = max (G, [ ], 2) is a column vector with C(i) = max (G (i,:)) +% C = max (A, [ ], 'all') is a scalar, with the largest entry in A. +% C = max (A, [ ], 1) is a row vector with C(j) = max (A (:,j)) +% C = max (A, [ ], 2) is a column vector with C(i) = max (A (i,:)) % % The 2nd output of [C,I] = max (...) in the MATLAB built-in max % is not yet supported. The max (..., nanflag) option is % not yet supported; only the 'omitnan' behavior is supported. % -% See also min. +% Complex matrices are not supported. +% +% See also GrB/min. + +% FUTURE: max(A,B) for two matrices A and B is slower than it could be. +% See comments in gb_union_op. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end -G = varargin {1} ; -[m, n] = size (G) ; -if (isequal (GrB.type (G), 'logical')) +type = gbtype (A) ; +if (contains (type, 'complex')) + error ('complex matrices not yet supported') ; +elseif (isequal (type, 'logical')) op = '|.logical' ; else op = 'max' ; end -desc = struct ('in0', 'transpose') ; - if (nargin == 1) - - % C = max (G) - if (isvector (G)) - % C = max (G) for a vector G results in a scalar C - C = GrB.reduce (op, G) ; - if (~GrB.isfull (G)) - C = max (C, 0) ; % recursively, on a scalar - end - else - % C = max (G) reduces each column to a scalar, - % giving a 1-by-n row vector. - C = GrB.vreduce (op, G, desc) ; - % if C(j) < 0, but the column is sparse, then assign C(j) = 0. - coldegree = GrB.entries (G, 'col', 'degree') ; - C = GrB.subassign (C, (C < 0) & (coldegree < m), 0)' ; - end - + % C = max (A) + C = GrB (gb_max1 (op, A)) ; elseif (nargin == 2) - % C = max (A,B) - A = varargin {1} ; - B = varargin {2} ; - if (isscalar (A)) - if (isscalar (B)) - % both A and B are scalars. Result is also a scalar. - C = gb_sparse_comparator (A, op, B) ; - else - % A is a scalar, B is a matrix - if (gb_get_scalar (A) > 0) - % since A > 0, the result is full - [m, n] = size (B) ; - % A (1:m,1:n) = A and cast to the type of B - A = GrB.subassign (GrB (m, n, GrB.type (B)), A) ; - else - % since A <= 0, the result is sparse. Expand the scalar A - % to the pattern of B. - A = GrB.expand (A, B) ; - end - C = GrB.eadd (A, op, B) ; - end - else - if (isscalar (B)) - % A is a matrix, B is a scalar - if (gb_get_scalar (B) > 0) - % since B > 0, the result is full - [m, n] = size (A) ; - % B (1:m,1:n) = B and cast to the type of A - B = GrB.subassign (GrB (m, n, GrB.type (A)), B) ; - else - % since B <= 0, the result is sparse. Expand the scalar B - % to the pattern of A. - B = GrB.expand (B, A) ; - end - C = GrB.eadd (A, op, B) ; - else - % both A and B are matrices. Result is sparse. - C = gb_sparse_comparator (A, op, B) ; - end + if (isobject (B)) + B = B.opaque ; end - -elseif (nargin == 3) - - % C = max (G, [ ], option) - option = varargin {3} ; - if (isequal (option, 'all')) - % C = max (G, [ ] 'all'), reducing all entries to a scalar - C = GrB.reduce (op, G) ; - if (~GrB.isfull (G)) - C = max (C, 0) ; % recursively, on a scalar - end - elseif (isequal (option, 1)) - % C = max (G, [ ], 1) reduces each column to a scalar, - % giving a 1-by-n row vector. - C = GrB.vreduce (op, G, desc) ; - % if C(j) < 0, but the column is sparse, then assign C(j) = 0. - coldegree = GrB.entries (G, 'col', 'degree') ; - C = GrB.subassign (C, (C < 0) & (coldegree < m), 0)' ; - elseif (isequal (option, 2)) - % C = max (G, [ ], 2) reduces each row to a scalar, - % giving an m-by-1 column vector. - C = GrB.vreduce (op, G) ; - % if C(i) < 0, but the row is sparse, then assign C(i) = 0. - rowdegree = GrB.entries (G, 'row', 'degree') ; - C = GrB.subassign (C, (C < 0) & (rowdegree < n), 0) ; - else - gb_error ('unknown option') ; - end - + C = GrB (gb_max2 (op, A, B)) ; else - gb_error ('invalid usage') ; + % C = max (A, [ ], option) + if (~isempty (B)) + error ('dimension argument not allowed with 2 input matrices') ; + end + C = GrB (gb_max3 (op, A, option)) ; end diff --git a/GraphBLAS/@GrB/min.m b/GraphBLAS/@GrB/min.m index 6c250b219e..b7543d5017 100644 --- a/GraphBLAS/@GrB/min.m +++ b/GraphBLAS/@GrB/min.m @@ -1,126 +1,56 @@ -function C = min (varargin) -%MIN Minimum elements of a GraphBLAS or MATLAB matrix. -% -% C = min (G) is the smallest entry in the vector G. If G is a matrix, -% C is a row vector with C(j) = min (G (:,j)). +function C = min (A, B, option) +%MIN Maximum elements of a matrix. +% C = min (A) is the smallest entry in the vector A. If A is a matrix, +% C is a row vector with C(j) = min (A (:,j)). % % C = min (A,B) is an array of the element-wise minimum of two matrices % A and B, which either have the same size, or one can be a scalar. -% Either A and/or B can be GraphBLAS or MATLAB matrices. % -% C = min (G, [ ], 'all') is a scalar, with the smallest entry in G. -% C = min (G, [ ], 1) is a row vector with C(j) = min (G (:,j)) -% C = min (G, [ ], 2) is a column vector with C(i) = min (G (i,:)) +% C = min (A, [ ], 'all') is a scalar, with the smallest entry in A. +% C = min (A, [ ], 1) is a row vector with C(j) = min (A (:,j)) +% C = min (A, [ ], 2) is a column vector with C(i) = min (A (i,:)) +% +% The 2nd output of [C,I] = min (...) in the MATLAB built-in min +% is not yet supported. The min (..., nanflag) option is +% not yet supported; only the 'omitnan' behavior is supported. % -% The indices of the minimum entry, or [C,I] = min (...) in the MATLAB -% built-in min function, are not computed. The min (..., nanflag) option -% is not available; only the 'includenan' behavior is supported. +% Complex matrices are not supported. % -% See also max. +% See also GrB/max. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% FUTURE: min(A,B) for two matrices A and B is slower than it could be. +% See comments in gb_union_op. -G = varargin {1} ; -[m,n] = size (G) ; +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end -if (isequal (GrB.type (G), 'logical')) +type = gbtype (A) ; +if (contains (type, 'complex')) + error ('complex matrices not yet supported') ; +elseif (isequal (type, 'logical')) op = '&.logical' ; else op = 'min' ; end -desc = struct ('in0', 'transpose') ; if (nargin == 1) - - % C = min (G) - if (isvector (G)) - % C = min (G) for a vector G results in a scalar C - C = GrB.reduce (op, G) ; - if (~GrB.isfull (G)) - C = min (C, 0) ; - end - else - % C = min (G) reduces each column to a scalar, - % giving a 1-by-n row vector. - C = GrB.vreduce (op, G, desc) ; - % if C(j) > 0, but the column is sparse, then assign C(j) = 0. - coldegree = GrB.entries (G, 'col', 'degree') ; - C = GrB.subassign (C, (C > 0) & (coldegree < m), 0)' ; - end - + % C = min (A) + C = GrB (gb_min1 (op, A)) ; elseif (nargin == 2) - % C = min (A,B) - A = varargin {1} ; - B = varargin {2} ; - if (isscalar (A)) - if (isscalar (B)) - % both A and B are scalars. Result is also a scalar. - C = gb_sparse_comparator (A, op, B) ; - else - % A is a scalar, B is a matrix - if (gb_get_scalar (A) < 0) - % since A < 0, the result is full - [m, n] = size (B) ; - % A (1:m,1:n) = A and cast to the type of B - A = GrB.subassign (GrB (m, n, GrB.type (B)), A) ; - else - % since A >= 0, the result is sparse. Expand the scalar A - % to the pattern of B. - A = GrB.expand (A, B) ; - end - C = GrB.eadd (A, op, B) ; - end - else - if (isscalar (B)) - % A is a matrix, B is a scalar - if (gb_get_scalar (B) < 0) - % since B < 0, the result is full - [m, n] = size (A) ; - % B (1:m,1:n) = B and cast to the type of A - B = GrB.subassign (GrB (m, n, GrB.type (A)), B) ; - else - % since B >= 0, the result is sparse. Expand the scalar B - % to the pattern of A. - B = GrB.expand (B, A) ; - end - C = GrB.eadd (A, op, B) ; - else - % both A and B are matrices. Result is sparse. - C = gb_sparse_comparator (A, op, B) ; - end - end - -elseif (nargin == 3) - - % C = min (G, [ ], option) - option = varargin {3} ; - if (isequal (option, 'all')) - % C = min (G, [ ] 'all'), reducing all entries to a scalar - C = GrB.reduce (op, G) ; - if (~GrB.isfull (G)) - C = min (C, 0) ; - end - elseif (isequal (option, 1)) - % C = min (G, [ ], 1) reduces each column to a scalar, - % giving a 1-by-n row vector. - C = GrB.vreduce (op, G, desc) ; - % if C(j) > 0, but the column is sparse, then assign C(j) = 0. - coldegree = GrB.entries (G, 'col', 'degree') ; - C = GrB.subassign (C, (C > 0) & (coldegree < m), 0)' ; - elseif (isequal (option, 2)) - % C = min (G, [ ], 2) reduces each row to a scalar, - % giving an m-by-1 column vector. - C = GrB.vreduce (op, G) ; - % if C(i) > 0, but the row is sparse, then assign C(i) = 0. - rowdegree = GrB.entries (G, 'row', 'degree') ; - C = GrB.subassign (C, (C > 0) & (rowdegree < n), 0) ; - else - gb_error ('unknown option') ; + if (isobject (B)) + B = B.opaque ; end - + C = GrB (gb_min2 (op, A, B)) ; else - gb_error ('invalid usage') ; + % C = min (A, [ ], option) + if (~isempty (B)) + error ('dimension argument not allowed with 2 input matrices') ; + end + C = GrB (gb_min3 (op, A, option)) ; end diff --git a/GraphBLAS/@GrB/minus.m b/GraphBLAS/@GrB/minus.m index 4ee677691c..14bce3ea57 100644 --- a/GraphBLAS/@GrB/minus.m +++ b/GraphBLAS/@GrB/minus.m @@ -3,16 +3,25 @@ % C = A-B subtracts the two matrices A and B. If A and B are matrices, % the pattern of C is the set union of A and B. If one of A or B is a % scalar, the scalar is expanded into a dense matrix the size of the -% other matrix, and the result is a dense matrix. If the type of A and B -% differ, the type of A is used, as: C = A - GrB (B, GrB.type (A)). +% other matrix, and the result is a dense matrix. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% -% See also GrB.eadd, plus, uminus. +% See also GrB.eadd, GrB/plus, GrB/uminus. + +% FUTURE: minus(A,B) for two matrices A and B is slower than it could be. +% See comments in gb_union_op. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +type = gboptype (gbtype (A), gbtype (B)) ; -C = A + (-B) ; +C = GrB (gb_eadd (A, '+', gbapply (['-.' type], B))) ; diff --git a/GraphBLAS/@GrB/mis.m b/GraphBLAS/@GrB/mis.m index d38cdaa143..2c5ef76aff 100644 --- a/GraphBLAS/@GrB/mis.m +++ b/GraphBLAS/@GrB/mis.m @@ -1,20 +1,17 @@ function iset = mis (A, check) %GRB.MIS variant of Luby's maximal independent set algorithm. % -% Usage: -% % iset = GrB.mis (A) ; % % Given an n-by-n symmetric adjacency matrix A of an undirected graph, -% compute a maximal set of independent nodes and return it in a boolean -% n-vector, 'iset' where iset(i) of true implies node i is a member of +% GrB.mis (A) finds a maximal set of independent nodes and returns it as a +% logical vector, iset, where iset(i) of true implies node i is a member of % the set. % -% The matrix A must not have any diagonal entries (self edges), and it -% must be symmetric. These conditions are not checked by default, and -% results are undefined if they do not hold. In particular, diagonal -% entries will cause the method to stall. To check these conditions, -% use: +% The matrix A must not have any diagonal entries (self edges), and it must +% be symmetric. These conditions are not checked by default, and results +% are undefined if they do not hold. In particular, diagonal entries will +% cause the method to stall. To check these conditions, use: % % iset = GrB.mis (A, 'check') ; % @@ -25,12 +22,14 @@ % % See also GrB.offdiag. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +% NOTE: this is a high-level algorithm that uses GrB objects. [m, n] = size (A) ; if (m ~= n) - gb_error ('A must be square') ; + error ('A must be square') ; end % convert A to logical @@ -42,16 +41,16 @@ if (isequal (check, 'check')) check = true ; else - gb_error ('unknown option') ; + error ('unknown option') ; end end if (check) if (nnz (diag (A)) > 0) - gb_error ('A must not have any diagonal entries') ; + error ('A must not have any diagonal entries') ; end if (~issymmetric (A)) - gb_error ('A must be symmetric') ; + error ('A must be symmetric') ; end end @@ -82,7 +81,7 @@ % add all singletons to iset % iset (degree == 0) = 1 -iset = GrB.assign (iset, degrees, true, sr_desc) ; +iset = GrB.assign (iset, degrees, true, sr_desc) ; % Iterate while there are candidates to check. ncand = GrB.entries (candidates) ; @@ -91,7 +90,7 @@ while (ncand > 0) % compute a random probability scaled by inverse of degree - % NOTE: this is slower than it should be; rand may not be parallel, + % FUTURE: this is slower than it should be; rand may not be parallel, % See GraphBLAS/Demo/Source/mis.c and the prand_* functions for a better % approach using user-defined types and operators. prob = 0.0001 + rand (n,1) ./ (1 + 2 * degrees) ; @@ -127,7 +126,7 @@ % this will not occur, unless the input is corrupted somehow if (last_ncand == ncand) - gb_error ('method stalled; rerun with ''check'' option') ; + error ('method stalled; rerun with ''check'' option') ; end last_ncand = ncand ; end diff --git a/GraphBLAS/@GrB/mldivide.m b/GraphBLAS/@GrB/mldivide.m index 790534de5a..0f524d7a92 100644 --- a/GraphBLAS/@GrB/mldivide.m +++ b/GraphBLAS/@GrB/mldivide.m @@ -1,19 +1,13 @@ function C = mldivide (A, B) % C = A\B, matrix left division. -% % If A is a scalar, then C = A.\B is computed; see 'help ldivide'. % Otherwise, C is computed by first converting A and B to MATLAB sparse % matrices, and then C=A\B is computed using the MATLAB backslash. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% % See also GrB/mrdivide. -% FUTURE: add solvers over a group (GF(2) for example). - -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. if (isscalar (A)) C = rdivide (B, A) ; diff --git a/GraphBLAS/@GrB/monoidinfo.m b/GraphBLAS/@GrB/monoidinfo.m index 2a2e38e0a2..89bcd7f9df 100644 --- a/GraphBLAS/@GrB/monoidinfo.m +++ b/GraphBLAS/@GrB/monoidinfo.m @@ -1,43 +1,53 @@ function monoidinfo (monoid, type) %GRB.MONOIDINFO list the details of a GraphBLAS monoid. % -% Usage -% % GrB.monoidinfo % GrB.monoidinfo (monoid) % GrB.monoidinfo (monoid, type) % -% For GrB.monoidinfo(op), the op must be a string of the form -% 'op.type', where 'op' is listed below. The second usage allows the -% type to be omitted from the first argument, as just 'op'. This is -% valid for all GraphBLAS operations, since the type defaults to the -% type of the input matrices. However, GrB.monoidinfo does not have a -% default type and thus one must be provided, either in the op as -% GrB.monoidinfo ('+.double'), or in the second argument, -% GrB.monoidinfo ('+', 'double'). -% -% The MATLAB interface to GraphBLAS provides for 44 different -% monoids. The valid monoids are: '+', '*', 'max', and 'min' for all -% but the 'logical' type, and '|', '&', 'xor', and 'eq' for the -% 'logical' type. +% For GrB.monoidinfo(op), the op must be a string of the form 'op.type', +% where 'op' is listed below. The second usage allows the type to be +% omitted from the first argument, as just 'op'. This is valid for all +% GraphBLAS operations, since the type defaults to the type of the input +% matrices. However, GrB.monoidinfo does not have a default type and thus +% one must be provided, either in the op as GrB.monoidinfo ('+.double'), or +% in the second argument, GrB.monoidinfo ('+', 'double'). +% +% A monoid is any binary operator z=f(x,y) that is commutative and +% associative, with an identity value o so that f(x,o)=f(o,x)=o. The types +% of z, x, and y must all be identical. For example, the plus.double +% operator is f(x,y)=x+y, with zero as the identity value (x+0 = 0+x = x). +% The times monoid has an identity value of 1 (since x*1 = 1*x = x). The +% identity of min.double is -inf. +% +% The valid monoids for real non-logical types are: +% '+', '*', 'max', 'min', 'any' +% For the 'logical' type: +% '|', '&', 'xor', 'eq', 'any' +% For complex types: +% '+', '*', 'any' +% For integer types (signed and unsigned): +% 'bitor', 'bitand', 'bitxor', 'bitxnor' +% +% Some monoids have synonyms; see 'help GrB.binopinfo' for details. % % Example: % % % valid monoids % GrB.monoidinfo ('+.double') ; % GrB.monoidinfo ('*.int32') ; +% GrB.monoidinfo ('min.double') ; % % % invalid monoids % GrB.monoidinfo ('1st.int32') ; % GrB.monoidinfo ('abs.double') ; +% GrB.monoidinfo ('min.complex') ; % -% See also GrB.binopinfo, GrB.descriptorinfo, % GrB.selectopinfo, +% See also GrB.binopinfo, GrB.descriptorinfo, GrB.selectopinfo, % GrB.semiringinfo, GrB.unopinfo. -% FUTURE: add complex monoids - -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. if (nargin == 0) help GrB.monoidinfo diff --git a/GraphBLAS/@GrB/mpower.m b/GraphBLAS/@GrB/mpower.m index a10c7e2910..07c5d7a32e 100644 --- a/GraphBLAS/@GrB/mpower.m +++ b/GraphBLAS/@GrB/mpower.m @@ -1,54 +1,50 @@ function C = mpower (A, B) -%A^B Matrix power. +%A^B matrix power. % C = A^B computes the matrix power of A raised to the B. A must be a % square matrix. B must an integer >= 0. % -% The inputs may be either GraphBLAS and/or MATLAB matrices/scalars, in -% any combination. C is returned as a GraphBLAS matrix. -% % See also GrB/power. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. - -[m, n] = size (A) ; +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -if (m ~= n) - gb_error ('For C=A^B, A must be square') ; +if (isobject (A)) + A = A.opaque ; end -if (~isscalar (B)) - gb_error ('For C=A^B, B must be a non-negative integer scalar') ; +if (isobject (B)) + B = B.opaque ; end +[am, an, atype] = gbsize (A) ; +[bm, bn] = gbsize (B) ; +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; -b = gb_get_scalar (B) ; -if (isreal (b) && isfinite (b) && round (b) == b && b >= 0) +if (a_is_scalar && b_is_scalar) + C = GrB (gb_power (A, B)) ; +else + if (am ~= an) + error ('For C=A^B, A must be square') ; + end + if (~b_is_scalar) + error ('For C=A^B, B must be a non-negative integer scalar') ; + end + b = gb_scalar (B) ; + if (~(isreal (b) && isfinite (b) && round (b) == b && b >= 0)) + error ('For C=A^B, B must be a non-negative integer scalar') ; + end if (b == 0) - % C is identity, of the same type as A - % FUTURE: ones (...) needs to be 'double' if A is complex. - C = GrB.build (1:n, 1:n, ones (1, n, GrB.type (A)), n, n) ; + % C = A^0 = I + if (isequal (atype, 'single complex')) + atype = 'single' ; + elseif (isequal (atype, 'double complex')) + atype = 'double' ; + end + C = GrB (gb_speye ('mpower', an, atype)) ; else % C = A^b where b > 0 is an integer - C = compute_mpower (A, b) ; - end -else - gb_error ('For C=A^B, B must be a non-negative integer scalar') ; -end - -end - -function C = compute_mpower (A, b) -% C = A^b where b > 0 is an integer -if (b == 1) - C = A ; -else - T = compute_mpower (A, floor (b/2)) ; - C = T*T ; - clear T ; - if (mod (b, 2) == 1) - C = C*A ; + C = GrB (gb_mpower (A, b)) ; end end -end diff --git a/GraphBLAS/@GrB/mrdivide.m b/GraphBLAS/@GrB/mrdivide.m index 34dd51c5e7..3414f240bd 100644 --- a/GraphBLAS/@GrB/mrdivide.m +++ b/GraphBLAS/@GrB/mrdivide.m @@ -1,19 +1,13 @@ function C = mrdivide (A, B) % C = A/B, matrix right division. -% % If A is a scalar, then C = A./B is computed; see 'help rdivide'. % Otherwise, C is computed by first converting A and B to MATLAB sparse % matrices, and then C=A/B is computed using the MATLAB backslash. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% % See also GrB/mldivide. -% FUTURE: add solvers over a group (GF(2) for example). - -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. if (isscalar (B)) C = rdivide (A, B) ; diff --git a/GraphBLAS/@GrB/mtimes.m b/GraphBLAS/@GrB/mtimes.m index 799bb30732..53c6a95a46 100644 --- a/GraphBLAS/@GrB/mtimes.m +++ b/GraphBLAS/@GrB/mtimes.m @@ -1,21 +1,24 @@ function C = mtimes (A, B) %MTIMES sparse matrix-matrix multiplication over the standard semiring. -% C=A*B multiples two matrices using the standard '+.*' semiring, If the -% type of A and B differ, the type of A is used. That is, C=A*B is the -% same as C = GrB.mxm (['+.*' GrB.type(A)], A, B). If either A or B are -% scalars, C=A*B is the same as C=A.*B. +% C=A*B multiples two matrices using the standard '+.*' semiring. If +% either A or B are scalars, C=A*B is the same as C=A.*B. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% -% See also GrB.mxm, GrB.emult, times. +% See also GrB.mxm, GrB.emult, GrB/times. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end -if (isscalar (A) || isscalar (B)) - C = A .* B ; +if (gb_isscalar (A) || gb_isscalar (B)) + C = GrB (gb_emult (A, '*', B)) ; else - C = GrB.mxm (A, '+.*', B) ; + C = GrB (gbmxm (A, '+.*', B)) ; end diff --git a/GraphBLAS/@GrB/mxm.m b/GraphBLAS/@GrB/mxm.m index cfbe3c9dee..5b0f3ec366 100644 --- a/GraphBLAS/@GrB/mxm.m +++ b/GraphBLAS/@GrB/mxm.m @@ -1,32 +1,30 @@ -function Cout = mxm (varargin) +function C = mxm (arg1, arg2, arg3, arg4, arg5, arg6, arg7) %GRB.MXM sparse matrix-matrix multiplication. % % GrB.mxm computes C = accum (C, A*B) using a given semiring. % % Usage: % -% Cout = GrB.mxm (semiring, A, B) -% Cout = GrB.mxm (semiring, A, B, desc) +% C = GrB.mxm (semiring, A, B) +% C = GrB.mxm (semiring, A, B, desc) % -% Cout = GrB.mxm (Cin, accum, semiring, A, B) -% Cout = GrB.mxm (Cin, accum, semiring, A, B, desc) +% C = GrB.mxm (Cin, accum, semiring, A, B) +% C = GrB.mxm (Cin, accum, semiring, A, B, desc) % -% Cout = GrB.mxm (Cin, M, semiring, A, B) -% Cout = GrB.mxm (Cin, M, semiring, A, B, desc) +% C = GrB.mxm (Cin, M, semiring, A, B) +% C = GrB.mxm (Cin, M, semiring, A, B, desc) % -% Cout = GrB.mxm (Cin, M, accum, semiring, A, B) -% Cout = GrB.mxm (Cin, M, accum, semiring, A, B, desc) -% -% Not all inputs are required. +% C = GrB.mxm (Cin, M, accum, semiring, A, B) +% C = GrB.mxm (Cin, M, accum, semiring, A, B, desc) % % Cin is an optional input matrix. If Cin is not present or is an empty -% matrix (Cin = [ ]) then it is implicitly a matrix with no entries, of -% the right size (which depends on A, B, and the descriptor). Its type -% is the output type of the accum operator, if it is present; otherwise, -% its type is the type of the additive monoid of the semiring. +% matrix (Cin = [ ]) then it is implicitly a matrix with no entries, of the +% right size (which depends on A, B, and the descriptor). Its type is the +% output type of the accum operator, if it is present; otherwise, its type +% is the type of the additive monoid of the semiring. % -% M is the optional mask matrix. If not present, or if empty, then no -% mask is used. If present, M must have the same size as C. +% M is the optional mask matrix. If not present, or if empty, then no mask +% is used. If present, M must have the same size as C. % % If accum is not present, then the operation becomes C<...> = A*B. % Otherwise, accum (C,A*B) is computed. The accum operator acts like a @@ -35,22 +33,14 @@ % The semiring is a required string defining the semiring to use, in the % form 'add.mult.type', where '.type' is optional. For example, % '+.*.double' is the conventional semiring for numerical linear algebra, -% used in MATLAB for C=A*B when A and B are double. If A or B are -% complex, then the '+.*.complex' semiring is used (once complex matrice -% are supported). GraphBLAS has many more semirings it can use. See -% 'help GrB.semiringinfo' for more details. -% -% A and B are the input matrices. They are transposed on input if -% desc.in0 = 'transpose' (which transposes A), and/or desc.in1 = -% 'transpose' (which transposes B). +% used in MATLAB for C=A*B when A and B are double. If A or B are double +% complex, then C=A*B uses the '+.*.double complex' semiring. GraphBLAS has +% many more semirings. See 'help GrB.semiringinfo' for more details. % -% The descriptor desc is optional. If not present, all default settings -% are used. Fields not present are treated as their default values. See -% 'help GrB.descriptorinfo' for more details. +% A and B are the input matrices. A is transposed on input if desc.in0 +% is 'transpose', and/or desc.in1 = 'transpose' transposes B. % -% All input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. Cout is returned as a GraphBLAS matrix, by default; -% see 'help GrB/descriptorinfo' for more options. +% desc is optional. See 'help GrB.descriptorinfo' for more details. % % Examples: % @@ -64,15 +54,49 @@ % C3 = E ; AB = A*B ; C3 (M) = C3 (M) + AB (M) ; % norm (C2-C3,1) % -% See also GrB.descriptorinfo, GrB.add, mtimes. +% See also GrB.descriptorinfo, GrB.add, GrB/mtimes. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (arg1)) + arg1 = arg1.opaque ; +end + +if (isobject (arg2)) + arg2 = arg2.opaque ; +end + +if (isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +if (nargin > 4 && isobject (arg5)) + arg5 = arg5.opaque ; +end + +if (nargin > 5 && isobject (arg6)) + arg6 = arg6.opaque ; +end -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +switch (nargin) + case 3 + [C, k] = gbmxm (arg1, arg2, arg3) ; + case 4 + [C, k] = gbmxm (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbmxm (arg1, arg2, arg3, arg4, arg5) ; + case 6 + [C, k] = gbmxm (arg1, arg2, arg3, arg4, arg5, arg6) ; + case 7 + [C, k] = gbmxm (arg1, arg2, arg3, arg4, arg5, arg6, arg7) ; +end -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - Cout = GrB (gbmxm (args {:})) ; -else - Cout = gbmxm (args {:}) ; +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/ne.m b/GraphBLAS/@GrB/ne.m index 322d35c7a4..7d29ed28f3 100644 --- a/GraphBLAS/@GrB/ne.m +++ b/GraphBLAS/@GrB/ne.m @@ -1,13 +1,13 @@ function C = ne (A, B) -%A ~= B Not equal. +%A ~= B not equal. % C = (A ~= B) is an element-by-element comparison of A and B. One or % both may be scalars. Otherwise, A and B must have the same size. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% % See also GrB/lt, GrB/le, GrB/gt, GrB/ge, GrB/eq. +% FUTURE: ne(A,B) for two matrices A and B is slower than it could be. +% See comments in gb_union_op. + % The pattern of C depends on the type of inputs: % A scalar, B scalar: C is scalar. % A scalar, B matrix: C is full if A~=0, otherwise C is a subset of B. @@ -15,54 +15,60 @@ % A matrix, B matrix: C is sparse, with the pattern of A+B. % Zeroes are then dropped from C after it is computed. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +[am, an, atype] = gbsize (A) ; +[bm, bn, btype] = gbsize (B) ; +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; +ctype = gboptype (atype, btype) ; -if (isscalar (A)) - if (isscalar (B)) +if (a_is_scalar) + if (b_is_scalar) % both A and B are scalars. C is sparse. - C = gb_sparse_comparator (A, '~=', B) ; + C = GrB (gb_union_op ('~=', A, B)) ; else % A is a scalar, B is a matrix - if (gb_get_scalar (A) ~= 0) + if (gb_scalar (A) ~= 0) % since a ~= 0, entries not present in B result in a true % value, so the result is dense. Expand A to a dense matrix. - [m, n] = size (B) ; - % A (1:m,1:n) = A and cast to the type of B - A = GrB.subassign (GrB (m, n, GrB.type (B)), A) ; - if (~GrB.isfull (B)) - B = full (B) ; - end - C = GrB.emult (A, '~=', B) ; + A = gb_scalar_to_full (bm, bn, ctype, A) ; + C = GrB (gbemult (A, '~=', gbfull (B, ctype))) ; else % since a == 0, entries not present in B result in a false % value, so the result is a sparse subset of B. select all % entries in B ~= 0, then convert to true. - C = GrB (B, 'logical') ; + C = GrB (gbnew (B, 'logical')) ; end end else - if (isscalar (B)) + if (b_is_scalar) % A is a matrix, B is a scalar - if (gb_get_scalar (B) ~= 0) + if (gb_scalar (B) ~= 0) % since b ~= 0, entries not present in A result in a true % value, so the result is dense. Expand B to a dense matrix. - [m, n] = size (A) ; - % B (1:m,1:n) = B and cast to the type of A - B = GrB.subassign (GrB (m, n, GrB.type (A)), B) ; - if (~GrB.isfull (A)) - A = full (A) ; - end - C = GrB.emult (A, '~=', B) ; + B = gb_scalar_to_full (am, an, ctype, B) ; + C = GrB (gbemult (gbfull (A, ctype), '~=', B)) ; else % since b == 0, entries not present in A result in a false - % value, so the result is a sparse subset of A. select all - % entries in A ~= 0, then convert to true. - C = GrB (A, 'logical') ; + % value, so the result is a sparse subset of A. Simply typecast + % A to logical. Explicit zeroes in A become explicit false + % entries. Any other explicit entries not equal to zero become + % true. + C = GrB (gbnew (A, 'logical')) ; end else % both A and B are matrices. C is sparse. - C = gb_sparse_comparator (A, '~=', B) ; + C = GrB (gb_union_op ('~=', A, B)) ; end end diff --git a/GraphBLAS/@GrB/nnz.m b/GraphBLAS/@GrB/nnz.m index b559faf2f3..8f2fc10d3e 100644 --- a/GraphBLAS/@GrB/nnz.m +++ b/GraphBLAS/@GrB/nnz.m @@ -1,13 +1,14 @@ function e = nnz (G) -%NNZ the number of nonzeros in a GraphBLAS matrix. +%NNZ the number of nonzeros in a matrix. % e = nnz (G) is the number of nonzeros in a GraphBLAS matrix G. A % GraphBLAS matrix G may have explicit zero entries, but these are % excluded from the count e. Thus, nnz (G) <= GrB.entries (G). % -% See also GrB.entries, GrB.prune, nonzeros, size, numel. +% See also GrB.entries, GrB.prune, GrB/nonzeros, GrB/size, GrB/numel. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -e = GrB.entries (G) - GrB.entries (GrB.select (G, '==0')) ; +G = G.opaque ; +e = gb_nnz (G) ; diff --git a/GraphBLAS/@GrB/nonz.m b/GraphBLAS/@GrB/nonz.m index 4ae218a050..11ade6769b 100644 --- a/GraphBLAS/@GrB/nonz.m +++ b/GraphBLAS/@GrB/nonz.m @@ -32,6 +32,9 @@ % 'zero' can be specified; d = GrB.nonz (A, ..., id). For example, to % count all entries in A not equal to one, use GrB.nonz (A, 1). % +% The result is a MATLAB scalar or vector, except for the 'degree' +% usage, in which case the result is a GrB vector d. +% % Example: % % A = magic (5) ; @@ -47,36 +50,45 @@ % GrB.nonz (S) % GrB.nonz (S, 'list') % -% See also GrB.entries, nnz, GrB/nnz, nonzeros, GrB/nonzeros, GrB.prune. +% See also GrB.entries, GrB/nnz, GrB/nonzeros, GrB.prune. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% issparse (G) is overloaded for a GraphBLAS matrix, and always returns -% true. Here, we need to know if A is truly a MATLAB sparse matrix, not -% a GraphBLAS sparse matrix. -matlab_sparse = builtin ('issparse', A) ; +matlab_sparse = false ; +if (isobject (A)) + % A is a GraphBLAS matrix; get its opaque content + A = A.opaque ; +elseif (builtin ('issparse', A)) + % A is a MATLAB sparse matrix + matlab_sparse = true ; +end -if (nargin > 1 && ~ischar (varargin {end})) - id = gb_get_scalar (varargin {end}) ; - if (id == 0 && matlab_sparse) - % id is zero, and A is a MATLAB sparse matrix, so no need to prune. - result = GrB.entries (A, varargin {1:end-1}) ; - else - % id is nonzero, so it can appear in any matrix (GraphBLAS, MATLAB - % sparse, or MATLAB full), so it must be pruned from A first. - result = GrB.entries (GrB.prune (A, id), varargin {1:end-1}) ; - end -else - if (matlab_sparse) - % id is not present so it defaults to zero, and A is MATLAB sparse - % matrix, so no need to prune explicit zeros from A. - result = GrB.entries (A, varargin {:}) ; - else - % A is a GraphBLAS matrix, or a MATLAB full matrix, so zeros - % must be pruned. This does not prune explicit zeros in a MATLAB - % full matrix. - result = GrB.entries (GrB.prune (A), varargin {:}) ; +% get the identity value +id = 0 ; +nargs = nargin ; +if (nargin > 1) + lastarg = varargin {nargs-1} ; + if (~ischar (lastarg)) + % the last argument is id, if it is not a string + id = gb_get_scalar (lastarg) ; + nargs = nargs - 1 ; end end +if (id ~= 0) + % id is nonzero, so prune A first (for any matrix A) + A = gbselect (A, '~=', id) ; +elseif (~matlab_sparse) + % id is zero, so prune A only if it is a GraphBLAS matrix + A = gbselect (A, 'nonzero') ; +end + +% get the count/list of the entries of A +result = gb_entries (A, varargin {1:nargs-1}) ; + +% if gb_entries returned a GraphBLAS struct, return it as a GrB matrix +if (isstruct (result)) + result = GrB (result) ; +end + diff --git a/GraphBLAS/@GrB/nonzeros.m b/GraphBLAS/@GrB/nonzeros.m index e3b0fdda6e..e90bdb445b 100644 --- a/GraphBLAS/@GrB/nonzeros.m +++ b/GraphBLAS/@GrB/nonzeros.m @@ -1,15 +1,16 @@ function X = nonzeros (G) -%NONZEROS extract entries from a GraphBLAS matrix. -% X = nonzeros (G) extracts the entries from a GraphBLAS matrix G. X has -% the same type as G ('double', 'single', 'int8', ...). If G contains -% explicit entries with a value of zero, these are dropped from X. Use -% [I,J,X] = find (G) or [I,J,X] = GrB.extracttuples (G) to return those -% entries. This function returns the X of [I,J,X] = find (GrB.prune(G)). +%NONZEROS extract entries from a matrix. +% X = nonzeros (G) extracts the entries from G. X has the same type as G +% ('double', 'single', 'int8', ...). If G contains explicit entries with a +% value of zero, these are dropped from X. To return those entries, use +% [I,J,X] = GrB.extracttuples (G). This function returns the X of +% [I,J,X] = find (G), which also drops explicit zeros. % -% See also GrB.extracttuples, GrB.entries, GrB.nonz, find. +% See also GrB.extracttuples, GrB.entries, GrB.nonz, GrB/find. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -X = gbextractvalues (gbselect ('nonzero', G.opaque, struct ('kind', 'GrB'))) ; +G = G.opaque ; +X = gbextractvalues (gbselect ('nonzero', G)) ; diff --git a/GraphBLAS/@GrB/norm.m b/GraphBLAS/@GrB/norm.m index b9c6c60b6e..c97c9fadef 100644 --- a/GraphBLAS/@GrB/norm.m +++ b/GraphBLAS/@GrB/norm.m @@ -1,6 +1,5 @@ -function s = norm (G,kind) -%NORM norm of a GraphBLAS sparse matrix. -% +function s = norm (G, kind) +%NORM matrix or vector norm. % If G is a matrix: % % norm (G,1) is the maximum sum of the columns of abs (G). @@ -17,19 +16,25 @@ % norm (G,inf) is the maximum of abs (G) % norm (G,-inf) is the minimum of abs (G) % +% The p-norm for vectors is not yet supported. +% % See also GrB.reduce, GrB.normdiff. -% FUTURE: the p-norm is not yet supported. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% FUTURE: add the p-norm for vectors. -if (nargin == 1) - kind = 2 ; +if (isobject (G)) + G = G.opaque ; end -if (isa (G, 'GrB')) - G = G.opaque ; +if (nargin == 2) + if (~ischar (kind)) + kind = gb_get_scalar (kind) ; + end +else + kind = 2 ; end s = gbnorm (G, kind) ; diff --git a/GraphBLAS/@GrB/normdiff.m b/GraphBLAS/@GrB/normdiff.m index 99bc195336..5b05774d9f 100644 --- a/GraphBLAS/@GrB/normdiff.m +++ b/GraphBLAS/@GrB/normdiff.m @@ -1,12 +1,11 @@ function s = normdiff (A,B,kind) %NORMDIFF norm (A-B,kind) -% % If A-B is a matrix: % % norm (A-B,1) is the maximum sum of the columns of abs (A-B). % norm (A-B,inf) is the maximum sum of the rows of abs (A-B). -% norm (A-B,'fro') is the Frobenius norm of A-B: the sqrt of the sum of the -% squares of the entries in A-B. +% norm (A-B,'fro') is the Frobenius norm of A-B: the sqrt of the sum of +% the squares of the entries in A-B. % The 2-norm is not available for either MATLAB or GraphBLAS sparse % matrices. % @@ -17,20 +16,20 @@ % norm (A-B,inf) is the maximum of abs (A-B) % norm (A-B,-inf) is the minimum of abs (A-B) % -% See also GrB.reduce, GrB.norm. +% See also GrB.reduce, GrB/norm. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. if (nargin < 3) kind = 2 ; end -if (isa (A, 'GrB')) +if (isobject (A)) A = A.opaque ; end -if (isa (B, 'GrB')) +if (isobject (B)) B = B.opaque ; end diff --git a/GraphBLAS/@GrB/not.m b/GraphBLAS/@GrB/not.m index 28d2f363e0..57bd57d9fb 100644 --- a/GraphBLAS/@GrB/not.m +++ b/GraphBLAS/@GrB/not.m @@ -1,15 +1,14 @@ function C = not (G) -%~ logical negation of a GraphBLAS matrix. -% C = ~G computes the logical negation of a GraphBLAS matrix G. The -% result C is dense, and the computation takes O(m*n) time and space, so -% sparsity is not exploited. To negate just the entries in the pattern -% of G, use C = GrB.apply ('~.logical', G), which has the same pattern as -% G. +%~ logical negation. +% C = ~G computes the logical negation of G. The result C is full. +% To negate just the entries in the pattern of G, use +% C = GrB.apply ('~.logical', G), which has the same pattern as G. % % See also GrB.apply. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB.apply ('~.logical', full (G)) ; +G = G.opaque ; +C = GrB (gbapply ('~', gbfull (G, 'logical'))) ; diff --git a/GraphBLAS/@GrB/numel.m b/GraphBLAS/@GrB/numel.m index d5b022ea9d..b8582ec5d8 100644 --- a/GraphBLAS/@GrB/numel.m +++ b/GraphBLAS/@GrB/numel.m @@ -1,18 +1,14 @@ function s = numel (G) -%NUMEL the maximum number of entries a GraphBLAS matrix can hold. -% numel (G) is m*n for the m-by-n GraphBLAS matrix G. -% If m, n, or m*n exceed flintmax (2^53), the result is returned as a vpa -% symbolic value, to avoid integer overflow. +%NUMEL the maximum number of entries in a matrix. +% numel (G) is m*n for the m-by-n GraphBLAS matrix G. If m, n, or m*n +% exceed flintmax (2^53), the result is returned as a vpa symbolic value, +% to avoid integer overflow. % -% See also nnz. +% See also GrB/nnz. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -[m, n] = size (G) ; -s = m*n ; - -if (m > flintmax || n > flintmax || s > flintmax) - s = vpa (vpa (m, 64) * vpa (n, 64), 64) ; -end +G = G.opaque ; +s = gb_numel (G) ; diff --git a/GraphBLAS/@GrB/nzmax.m b/GraphBLAS/@GrB/nzmax.m index 84183e93de..4b23469be3 100644 --- a/GraphBLAS/@GrB/nzmax.m +++ b/GraphBLAS/@GrB/nzmax.m @@ -1,14 +1,15 @@ function e = nzmax (G) -%NZMAX the number of entries in a GraphBLAS matrix. +%NZMAX maximum number of entries in a matrix. % Since the GraphBLAS data structure is opaque, nzmax (G) has no -% particular meaning. Thus, nzmax (G) is simply max (GrB.entries (G), 1). +% particular meaning. Thus, nzmax (G) is simply max (GrB.entries (G), 1). % It appears as an overloaded operator for a GrB matrix simply for % compatibility with MATLAB sparse matrices. % -% See also nnz, GrB.entries, GrB.nonz. +% See also GrB/nnz, GrB.entries, GrB.nonz. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -e = max (GrB.entries (G), 1) ; +G = G.opaque ; +e = max (gbnvals (G), 1) ; diff --git a/GraphBLAS/@GrB/offdiag.m b/GraphBLAS/@GrB/offdiag.m index 582d97ae99..99dd446c18 100644 --- a/GraphBLAS/@GrB/offdiag.m +++ b/GraphBLAS/@GrB/offdiag.m @@ -1,11 +1,15 @@ function C = offdiag (A) -%GRB.OFFDIAG removes diaogonal entries from the matrix A. +%GRB.OFFDIAG remove diaogonal entries. % C = GrB.offdiag (A) removes diagonal entries from A. % -% See also tril, triu, diag, GrB.select. +% See also GrB/tril, GrB/triu, GrB/diag, GrB.select. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB.select ('offdiag', A, 0) ; +if (isobject (A)) + A = A.opaque ; +end + +C = GrB (gbselect ('offdiag', A, 0)) ; diff --git a/GraphBLAS/@GrB/ones.m b/GraphBLAS/@GrB/ones.m index e6c23de9d8..fecd0d904f 100644 --- a/GraphBLAS/@GrB/ones.m +++ b/GraphBLAS/@GrB/ones.m @@ -1,13 +1,21 @@ function C = ones (varargin) -%ONES a matrix with all ones, the same type as G. -% C = ones (m, n, 'like', G) or C = ones ([m n], 'like', G) constructs an -% m-by-n GraphBLAS matrix C with all entries equal to one. C has the -% same type as G. +%ONES a matrix with all ones. % -% See also zeros, false, true. +% C = ones (n) ; n-by-n GrB double matrix of all ones. +% C = ones (m,n) ; m-by-n GrB double matrix of all ones. +% C = ones ([m,n]) ; m-by-n GrB double matrix of all ones. +% C = ones (..., type) ; matrix of all ones of given type. +% C = ones (..., 'like', G) ; matrix of all ones, same type as G. +% +% Since function overloads the MATLAB built-in ones(...), at least one +% input must be a GraphBLAS matrix to use this version; for example, +% C = ones (GrB (n), 'int8'). +% +% See also GrB/zeros, GrB/false, GrB/true. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB.subassign (zeros (varargin {:}), 1) ; +[m, n, type] = gb_parse_args ('ones', varargin {:}) ; +C = GrB (gb_scalar_to_full (m, n, type, 1)) ; diff --git a/GraphBLAS/@GrB/optype.m b/GraphBLAS/@GrB/optype.m new file mode 100644 index 0000000000..dde4fe5342 --- /dev/null +++ b/GraphBLAS/@GrB/optype.m @@ -0,0 +1,69 @@ +function type = optype (a, b) +%GRB.OPTYPE determine the default type of a binary operator. +% type = GrB.optype (a, b) returns a string that defines the +% default type of operator to use for two inputs A and B, of type +% atype and btype, respectively. The input a can be either the +% matrix A or the string atype = GrB.type (A), and likewise for b. +% +% The rules are listed below; the first one that applies is used: +% +% (1) same: +% +% if A and B have the same type: optype is the type of A and B. +% +% (2) any logical: +% +% if A or B are logical: optype is from the other operand. +% +% (3) both integer: +% +% if A and B are both integers (with ka and kb bits, respectively): +% optype is signed if either A or B are signed, and the optype has +% max(ka,kb) bits. For example, uint32*int8 uses an int32 optype. +% +% (4) mixing integer and floating-point: +% +% if one operand is any integer, and the other is any floating-point +% (single, double, single complex, or double complex): optype has +% the floating-point type of the other operand. +% +% (5) both floating-point: +% +% if A or B are single: optype is from the other operand. +% if A or B are double: if the other is single complex or double +% complex, optype is double complex; otherwise optype is double. +% if A or B are single complex: if the other operand is double or +% double complex, optype is double complex; otherwise it is single +% complex. +% if A or B are double complex: optype is double complex. +% +% Example: +% +% GrB.optype ('uint32', 'int8') +% GrB.optype (uint32 (magic (4)), rand (4)) +% +% See also GrB.binopinfo, GrB.semiringinfo, GrB.type. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (ischar (a)) + atype = a ; +elseif (isobject (a)) + a = a.opaque ; + atype = gbtype (a) ; +else + atype = gbtype (a) ; +end + +if (ischar (b)) + btype = b ; +elseif (isobject (b)) + b = b.opaque ; + btype = gbtype (b) ; +else + btype = gbtype (b) ; +end + +type = gboptype (atype, btype) ; + diff --git a/GraphBLAS/@GrB/or.m b/GraphBLAS/@GrB/or.m index da05404190..1c5a883fe5 100644 --- a/GraphBLAS/@GrB/or.m +++ b/GraphBLAS/@GrB/or.m @@ -2,40 +2,52 @@ %| logical OR. % C = (A | B) is the element-by-element logical OR of A and B. One or % both may be scalars. Otherwise, A and B must have the same size. -% GraphBLAS and MATLAB matrices may be combined. % -% See also GrB/and, GrB/xor. +% See also GrB/and, GrB/xor, GrB/not. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -if (isscalar (A)) - if (isscalar (B)) +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +[am, an, ~] = gbsize (A) ; +[bm, bn, ~] = gbsize (B) ; +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; + +if (a_is_scalar) + if (b_is_scalar) % A and B are scalars - C = GrB.emult (A, '|.logical', B) ; + C = GrB (gbemult (A, '|.logical', B)) ; else % A is a scalar, B is a matrix - if (gb_get_scalar (A) == 0) + if (gb_scalar (A) == 0) % A is false, so C is B typecasted to logical - C = GrB (B, 'logical') ; + C = GrB (gbnew (B, 'logical')) ; else % A is true, so C is a full matrix the same size as B - C = GrB (true (size (B))) ; + C = GrB (gb_scalar_to_full (bm, bn, 'logical', true)) ; end end else - if (isscalar (B)) + if (b_is_scalar) % A is a matrix, B is a scalar - if (gb_get_scalar (B) == 0) + if (gb_scalar (B) == 0) % B is false, so C is A typecasted to logical C = GrB (A, 'logical') ; else % B is true, so C is a full matrix the same size as A - C = GrB (true (size (A))) ; + C = GrB (gb_scalar_to_full (am, an, 'logical', true)) ; end else % both A and B are matrices. C is the set union of A and B - C = GrB.eadd (A, '|.logical', B) ; + C = GrB (gbeadd (A, '|.logical', B)) ; end end diff --git a/GraphBLAS/@GrB/pagerank.m b/GraphBLAS/@GrB/pagerank.m index daf8c010e3..b39a74d2cb 100644 --- a/GraphBLAS/@GrB/pagerank.m +++ b/GraphBLAS/@GrB/pagerank.m @@ -1,9 +1,9 @@ function [r, stats] = pagerank (A, opts) %GRB.PAGERANK PageRank of a graph. -% r = GrB.pagerank (A) computes the PageRank of a graph with adjacency matrix -% A. r = GrB.pagerank (A, options) allows for non-default options to be -% selected. For compatibility with MATLAB, defaults are identical to the -% MATLAB pagerank method in @graph/centrality and @digraph/centrality: +% r = GrB.pagerank (A) computes the PageRank of a graph with adjacency +% matrix A. r = GrB.pagerank (A, options) allows for non-default options +% to be selected. For compatibility with MATLAB, defaults are identical to +% the MATLAB pagerank method in @graph/centrality and @digraph/centrality: % % opts.tol = 1e-4 stopping criterion % opts.maxit = 100 maximum # of iterations to take @@ -11,22 +11,24 @@ % opts.weighted = false true: use edgeweights of A; false: use spones(A) % opts.type = 'double' compute in 'single' or 'double' precision % -% A can be a GraphBLAS or MATLAB matrix. A can have any format ('by row' or -% 'by col'), but GrB.pagerank is faster if A is 'by col'. +% A can be a GraphBLAS or MATLAB matrix. A can have any format ('by row' +% or 'by col'), but GrB.pagerank is faster if A is 'by col'. % % An optional 2nd output argument provides statistics: % stats.tinit initialization time % stats.trank pagerank time % stats.iter # of iterations taken % -% See also centrality. +% See also graph/centrality. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -%------------------------------------------------------------------------------- +% NOTE: this is a high-level algorithm that uses GrB objects. + +%------------------------------------------------------------------------- % initializations -%------------------------------------------------------------------------------- +%------------------------------------------------------------------------- tstart = tic ; @@ -51,7 +53,7 @@ end if (~(isequal (opts.type, 'single') || isequal (opts.type, 'double'))) - gb_error ('opts.type must be ''single'' or ''double''') ; + error ('opts.type must be ''single'' or ''double''') ; end % get options @@ -65,7 +67,7 @@ [m, n] = size (A) ; if (m ~= n) - gb_error ('A must be square') ; + error ('A must be square') ; end % select the semiring and determine if A is native @@ -100,9 +102,9 @@ d = GrB.subassign (d, { sinks }, 1) ; end -%------------------------------------------------------------------------------- +%------------------------------------------------------------------------- % compute the pagerank -%------------------------------------------------------------------------------- +%------------------------------------------------------------------------- stats.tinit = toc (tstart) ; tstart = tic ; diff --git a/GraphBLAS/@GrB/plus.m b/GraphBLAS/@GrB/plus.m index 764903275b..76b86cd003 100644 --- a/GraphBLAS/@GrB/plus.m +++ b/GraphBLAS/@GrB/plus.m @@ -2,37 +2,21 @@ %PLUS sparse matrix addition, C = A+B. % C = A+B adds the two matrices A and B. If A and B are matrices, the % pattern of C is the set union of A and B. If one of A or B is a -% scalar, the scalar is expanded into a dense matrix the size of the -% other matrix, and the result is a dense matrix. If the type of A and B -% differ, the type of A is used, as: C = A + GrB (B, GrB.type (A)). +% nonzero scalar, the scalar is expanded into a dense matrix the size of +% the other matrix, and the result is a dense matrix. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% -% See also GrB.eadd, minus, uminus. +% See also GrB.eadd, GrB/minus, GrB/uminus. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +if (isobject (A)) + A = A.opaque ; +end -if (isscalar (A)) - if (isscalar (B)) - % both A and B are scalars. Result is also a scalar. - else - % A is a scalar, B is a matrix. Result is full. - [m, n] = size (B) ; - % A (1:m,1:n) = A and cast to the type of B - A = GrB.subassign (GrB (m, n, GrB.type (B)), A) ; - end -else - if (isscalar (B)) - % A is a matrix, B is a scalar. Result is full. - [m, n] = size (A) ; - % B (1:m,1:n) = B and cast to the type of A - B = GrB.subassign (GrB (m, n, GrB.type (A)), B) ; - else - % both A and B are matrices. Result is sparse. - end +if (isobject (B)) + B = B.opaque ; end -C = GrB.eadd (A, '+', B) ; +C = GrB (gb_eadd (A, '+', B)) ; diff --git a/GraphBLAS/@GrB/pow2.m b/GraphBLAS/@GrB/pow2.m new file mode 100644 index 0000000000..4125661aed --- /dev/null +++ b/GraphBLAS/@GrB/pow2.m @@ -0,0 +1,41 @@ +function C = pow2 (A, B) +%POW2 base-2 power and scale floating-point number. +% C = pow2 (A) is C(i,j) = 2.^A(i,j) for each entry in A. +% Since 2^0 is nonzero, C is a full matrix. +% +% C = pow2 (F,E) is C = F .* (2 .^ fix (E)). C is sparse, with +% the same pattern as F+E. Any imaginary parts of F and E are ignored. +% +% See also GrB/log2, GrB/power, GrB/exp. + +% FUTURE: pow2(A,B) for two matrices A and B is slower than it could be. +% See comments in gb_union_op. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end +atype = gbtype (A) ; + +if (nargin == 1) + % C = 2.^A + if (~gb_isfloat (atype)) + atype = 'double' ; + end + C = GrB (gbapply ('pow2', gbfull (A, atype))) ; +else + % C = A.*(2.^B) + if (isobject (B)) + B = B.opaque ; + end + type = gboptype (atype, gbtype (B)) ; + if (contains (type, 'single')) + type = 'single' ; + else + type = 'double' ; + end + C = GrB (gb_union_op (['pow2.' type], A, B)) ; +end + diff --git a/GraphBLAS/@GrB/power.m b/GraphBLAS/@GrB/power.m index d65bc27acb..b403b625da 100644 --- a/GraphBLAS/@GrB/power.m +++ b/GraphBLAS/@GrB/power.m @@ -1,67 +1,21 @@ function C = power (A, B) -%.^ Array power. +%.^ array power. % C = A.^B computes element-wise powers. One or both of A and B may be -% scalars. Otherwise, A and B must have the same size. The computation -% takes O(m*n) time if the matrices are m-by-n, except in the case that -% B is a positive scalar (greater than zero). In that case, the pattern -% of C is a subset of the pattern of A. +% scalars. Otherwise, A and B must have the same size. C is sparse (with +% the same pattern as A) if B is a positive scalar (greater than zero), or +% full otherwise. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% -% Note that complex matrices are not yet supported. -% -% See also GrB/mpower. +% See also GrB/mpower, GrB/pow2, GrB/exp. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -if (isscalar (A)) - if (isscalar (B)) - % both A and B are scalars - A = full (A) ; - B = full (B) ; - else - % A is a scalar, B is a matrix; expand A to the size of B - [m, n] = size (B) ; - % A (1:m,1:n) = A, keeping its type - A = GrB.subassign (GrB (m, n, GrB.type (A)), A) ; - if (~GrB.isfull (B)) - B = full (B) ; - end - end -else - if (isscalar (B)) - % A is a matrix, B is a scalar - if (gb_get_scalar (B) <= 0) - % so the result is full - if (~GrB.isfull (A)) - A = full (A) ; - end - [m, n] = size (A) ; - % B (1:m,1:n) = B, keeping its type - B = GrB.subassign (GrB (m, n, GrB.type (B)), B) ; - else - % The scalar b is > 0, and thus 0.^b is zero. The result is - % sparse. B is expanded to a matrix with the same pattern as A. - B = GrB.expand (B, A) ; - end - else - % both A and B are matrices. - if (~GrB.isfull (A)) - A = full (A) ; - end - if (~GrB.isfull (B)) - B = full (B) ; - end - end +if (isobject (A)) + A = A.opaque ; +end +if (isobject (B)) + B = B.opaque ; end -% GraphBLAS does not have a binary operator f(x,y)=x^y. It could be -% constructed as a user-defined operator, but this is reasonably fast. -% FUTURE: create a binary operator f(x,y) = x^y. -[m, n] = size (A) ; -[~, ~, Ax] = GrB.extracttuples (A) ; -[I, J, Bx] = GrB.extracttuples (B) ; -C = GrB.build (I, J, (Ax .^ Bx), m, n) ; +C = GrB (gb_power (A, B)) ; diff --git a/GraphBLAS/@GrB/private/gb_abs.m b/GraphBLAS/@GrB/private/gb_abs.m new file mode 100644 index 0000000000..98bbfbe289 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_abs.m @@ -0,0 +1,13 @@ +function C = gb_abs (G) +%GB_ABS Absolute value of a GraphBLAS matrix. +% Implements C = abs (G) + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (gb_issigned (gbtype (G))) + C = gbapply ('abs', G) ; +else + C = G ; +end + diff --git a/GraphBLAS/@GrB/private/gb_bandwidth.m b/GraphBLAS/@GrB/private/gb_bandwidth.m new file mode 100644 index 0000000000..3b093dbbc1 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_bandwidth.m @@ -0,0 +1,20 @@ +function [lo, hi] = gb_bandwidth (G) +%GB_BANDWIDTH Determine the bandwidth of a GraphBLAS matrix. +% Implements [lo, hi] = bandwidth (G). + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +% compute the bandwidth +if (gbnvals (G) == 0) + % matrix is empty + hi = 0 ; + lo = 0 ; +else + desc.base = 'zero-based' ; + [i, j] = gbextracttuples (G, desc) ; + b = j - i ; + hi = max (0, double (max (b))) ; + lo = max (0, -double (min (b))) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_bitwise.m b/GraphBLAS/@GrB/private/gb_bitwise.m new file mode 100644 index 0000000000..bb2478a133 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_bitwise.m @@ -0,0 +1,82 @@ +function C = gb_bitwise (op, A, B, assumedtype) +%GB_BITWISE bitwise AND, OR, XOR, ... + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +atype = gbtype (A) ; +btype = gbtype (B) ; + +if (contains (atype, 'complex') || contains (btype, 'complex')) + error ('inputs must be real') ; +end + +if (isequal (atype, 'logical') || isequal (btype, 'logical')) + error ('inputs must not be logical') ; +end + +if (~contains (assumedtype, 'int')) + error ('assumedtype must be an integer type') ; +end + +% C will have the same type as A on input +ctype = atype ; + +if (isequal (atype, 'double') || isequal (atype, 'single')) + A = gbnew (A, assumedtype) ; + atype = assumedtype ; +end + +if (isequal (op, 'bitshift')) + + if (~isequal (btype, 'int8')) + % convert B to int8, and ensure all values are in range -64:64 + % ensure all entries in B are <= 64 + B = gbapply2 (['min.' btype], B, 64) ; + if (gb_issigned (btype)) + % ensure all entries in B are >= -64 + B = gbapply2 (['max.' btype], B, -64) ; + end + B = gbnew (B, 'int8') ; + end + + if (gb_isscalar (A) || gb_isscalar (B)) + % either A or B are scalars + C = gbapply2 (['bitshift.' atype], A, B) ; + else + % both A and B are matrices. + % expand B by padding it with zeros from the pattern of A + B = gbeadd ('1st.int8', B, gb_expand (0, A, 'int8')) ; + C = gbemult (['bitshift.' atype], A, B) ; + end + +else + + if (isequal (btype, 'double') || isequal (btype, 'single')) + B = gbnew (B, assumedtype) ; + btype = assumedtype ; + end + if (~isequal (atype, btype)) + error ('integer inputs must have the same type') ; + end + + switch (op) + case { 'bitxor', 'bitor' } + C = gb_eadd (A, op, B) ; + case { 'bitand' } + C = gb_emult (A, op, B) ; + end +end + +if (~isequal (gbtype (C), ctype)) + C = gbnew (C, ctype) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_convert_index_1d_to_2d.m b/GraphBLAS/@GrB/private/gb_convert_index_1d_to_2d.m index 36fa458f82..75d5aefd50 100644 --- a/GraphBLAS/@GrB/private/gb_convert_index_1d_to_2d.m +++ b/GraphBLAS/@GrB/private/gb_convert_index_1d_to_2d.m @@ -1,6 +1,9 @@ function [i, j] = gb_convert_index_1d_to_2d (k, m) %GB_CONVERT_INDEX_1D_TO_2D convert 1D indices to 2D -% the indices must be zero-based +% the indices must be zero-based. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. i = rem (k, m) ; j = (k - i) / m ; diff --git a/GraphBLAS/@GrB/private/gb_convert_index_2d_to_1d.m b/GraphBLAS/@GrB/private/gb_convert_index_2d_to_1d.m index 6aa48209ed..925d7b7d7b 100644 --- a/GraphBLAS/@GrB/private/gb_convert_index_2d_to_1d.m +++ b/GraphBLAS/@GrB/private/gb_convert_index_2d_to_1d.m @@ -1,6 +1,9 @@ function k = gb_convert_index_2d_to_1d (i, j, m) %GB_CONVERT_INDEX_2D_TO_1D convert 2D indices to 1D -% the indices must be zero-based +% the indices must be zero-based. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. k = i + j * m ; diff --git a/GraphBLAS/@GrB/private/gb_dense_comparator.m b/GraphBLAS/@GrB/private/gb_dense_comparator.m deleted file mode 100644 index bef67e7cfe..0000000000 --- a/GraphBLAS/@GrB/private/gb_dense_comparator.m +++ /dev/null @@ -1,21 +0,0 @@ -function C = gb_dense_comparator (A, op, B) -%GB_DENSE_COMPARATOR compare two matrices, first expanding them to full. -% The pattern of C is a full matrix. A and B must first be expanded to to -% a full matrix with explicit zeros. For example, with A <= B for two -% matrices A and B: -% -% in A in B A(i,j) <= B (i,j) true or false -% not in A in B 0 <= B(i,j) true or false -% in A not in B A(i,j) <= 0 true or false -% not in A not in B 0 <= 0 true, in C - -if (~GrB.isfull (A)) - A = full (A) ; -end - -if (~GrB.isfull (B)) - B = full (B) ; -end - -C = GrB.emult (A, op, B) ; - diff --git a/GraphBLAS/@GrB/private/gb_diag.m b/GraphBLAS/@GrB/private/gb_diag.m new file mode 100644 index 0000000000..1b337ff0bd --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_diag.m @@ -0,0 +1,76 @@ +function C = gb_diag (A, k) +%GB_DIAG Diagonal matrices and diagonals of a GraphBLAS matrix. +% Implements C = diag (A,k) + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[am, an, atype] = gbsize (A) ; +a_is_vector = (am == 1) || (an == 1) ; +desc.base = 'zero-based' ; + +if (a_is_vector) + + % C = diag (v,k) is an m-by-m matrix if v is a vector + n = am * an ; + m = n + abs (k) ; + + if (am == 1) + % A is a row vector + if (k >= 0) + [~, I, X] = gbextracttuples (A, desc) ; + J = I + int64 (k) ; + else + [~, J, X] = gbextracttuples (A, desc) ; + I = J - int64 (k) ; + end + else + % A is a column vector + if (k >= 0) + [I, ~, X] = gbextracttuples (A, desc) ; + J = I + int64 (k) ; + else + [J, ~, X] = gbextracttuples (A, desc) ; + I = J - int64 (k) ; + end + end + + C = gbbuild (I, J, X, m, m, desc) ; + +else + + % C = diag (A,k) is a column vector formed from the elements of the kth + % diagonal of A + + if (k >= 0) + m = min (an-k, am) ; + else + m = min (an, am+k) ; + end + + if (m == 0) + + % A does not have a kth diagonal so C is empty + I = [ ] ; + + else + + % extract the kth diagonal from A and convert into a column vector + C = gbselect ('diag', A, k) ; + if (k >= 0) + [I, ~, X] = gbextracttuples (C, desc) ; + else + [~, I, X] = gbextracttuples (C, desc) ; + end + + end + + if (isempty (I)) + % A does not have a kth diagonal, or diag (A,k) has no entries + C = gbnew (m, 1, atype) ; + else + C = gbbuild (I, int64 (0), X, m, 1, desc) ; + end + +end + diff --git a/GraphBLAS/@GrB/private/gb_eadd.m b/GraphBLAS/@GrB/private/gb_eadd.m new file mode 100644 index 0000000000..9ac223ea95 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_eadd.m @@ -0,0 +1,53 @@ +function C = gb_eadd (A, op, B) +%GB_EADD C = A+B, sparse matrix 'addition' using the given op. +% The pattern of C is the set union of A and B. This method assumes the +% identity value of the op is zero. That is, x+0 = x+0 = x. The binary +% operator op is only applied to entries in the intersection of the +% pattern of A and B. +% +% The inputs A and B are MATLAB matrices or GraphBLAS structs (not GrB +% objects). The result is a typically a GraphBLAS struct. +% +% See also GrB/plus, GrB/minus, GrB/bitxor, GrB/bitor, GrB/hypot. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com See GraphBLAS/Doc/License.txt. + +[am, an, atype] = gbsize (A) ; +[bm, bn, btype] = gbsize (B) ; +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; +type = gboptype (atype, btype) ; + +if (a_is_scalar) + if (b_is_scalar) + % both A and B are scalars. Result is also a scalar. + C = gbeadd (A, op, B) ; + else + % A is a scalar, B is a matrix. Result is full, unless A == 0. + if (gb_scalar (A) == 0) + % C = 0+B is a MATLAB matrix if B is a MATLAB matrix + C = B ; + else + % expand A to a full matrix + A = gb_scalar_to_full (bm, bn, type, A) ; + C = gbeadd (A, op, B) ; + end + end +else + if (b_is_scalar) + % A is a matrix, B is a scalar. Result is full, unless B == 0. + if (gb_scalar (B) == 0) + % C = A+0 is a MATLAB matrix if A is a MATLAB matrix + C = A ; + else + % expand B to a full matrix + B = gb_scalar_to_full (am, an, type, B) ; + C = gbeadd (A, op, B) ; + end + else + % both A and B are matrices. Result is sparse. + C = gbeadd (A, op, B) ; + end +end + diff --git a/GraphBLAS/@GrB/private/gb_emult.m b/GraphBLAS/@GrB/private/gb_emult.m new file mode 100644 index 0000000000..9a86db85a1 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_emult.m @@ -0,0 +1,22 @@ +function C = gb_emult (A, op, B) +%GB_EMULT C = A.*B, sparse matrix element-wise multiplication. +% C = gb_emult (A, op, B) computes the element-wise multiplication of A +% and B using the operator op, where the op is '*' for C=A.*B. If both A +% and B are matrices, the pattern of C is the intersection of A and B. If +% one is a scalar, the pattern of C is the same as the pattern of the one +% matrix. +% +% The input matrices may be either GraphBLAS structs and/or MATLAB matrices, +% in any combination. C is returned as a GraphBLAS struct. + +% SuiteSparse:GraphBLAS, T. A. Davis, (c) 2017-2020, All Rights Reserved. +% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. + +if (gb_isscalar (A) || gb_isscalar (B)) + % either A or B are scalars + C = gbapply2 (A, op, B) ; +else + % both A and B are matrices + C = gbemult (A, op, B) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_entries.m b/GraphBLAS/@GrB/private/gb_entries.m new file mode 100644 index 0000000000..7aa30a5474 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_entries.m @@ -0,0 +1,62 @@ +function result = gb_entries (A, varargin) +%GB_ENTRIES count or query the entries of a matrix. +% Implements GrB.entries (A, ...) and GrB.nonz (A, ...). + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +% get the string arguments +dim = 'all' ; % 'all', 'row', or 'col' +kind = 'count' ; % 'count', 'list', or 'degree' +for k = 1:nargin-1 + arg = varargin {k} ; + switch arg + case { 'all', 'row', 'col' } + dim = arg ; + case { 'count', 'list', 'degree' } + kind = arg ; + otherwise + error ('unknown option') ; + end +end + +if (isequal (dim, 'all')) + + switch kind + case 'count' + % number of entries in A + % e = GrB.entries (A) + result = gbnvals (A) ; + case 'list' + % list of values of unique entries + % X = GrB.entries (A, 'list') + result = unique (gbextractvalues (A)) ; + otherwise + error ('''all'' and ''degree'' cannot be combined') ; + end + +else + + % get the row or column degree + result = gbdegree (A, dim) ; + + switch kind + case 'count' + % number of non-empty rows/cols + % e = GrB.entries (A, 'row') + % e = GrB.entries (A, 'col') + result = gbnvals (gbselect (result, 'nonzero')) ; + case 'list' + % list of non-empty rows/cols + % I = GrB.entries (A, 'row', 'list') + % J = GrB.entries (A, 'col', 'list') + desc.base = 'one-based int' ; + result = gbextracttuples (gbselect (result, 'nonzero'), desc) ; + % case 'degree' + % degree of all rows/cols + % d = GrB.entries (A, 'row', 'degree') + % d = GrB.entries (A, 'col', 'degree') + % result is returned as a GraphBLAS struct, already computed above + end +end + diff --git a/GraphBLAS/@GrB/private/gb_error.m b/GraphBLAS/@GrB/private/gb_error.m deleted file mode 100644 index aed8aa21a0..0000000000 --- a/GraphBLAS/@GrB/private/gb_error.m +++ /dev/null @@ -1,8 +0,0 @@ -function gb_error (varargin) -%GB_ERROR report an error - -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. - -error ('GrB:error', varargin {:}) ; - diff --git a/GraphBLAS/@GrB/private/gb_expand.m b/GraphBLAS/@GrB/private/gb_expand.m new file mode 100644 index 0000000000..47bfeabece --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_expand.m @@ -0,0 +1,14 @@ +function C = gb_expand (scalar, S, type) +%GB_EXPAND expand a scalar into a GraphBLAS matrix. +% Implements C = GrB.expand (scalar, S, type). This function assumes the +% first input is a scalar; the caller has checked this already. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +% typecast the scalar to the desired type +scalar = gbnew (scalar, type) ; + +% expand the scalar into the pattern of S +C = gbapply2 (['1st.' type], scalar, S) ; + diff --git a/GraphBLAS/@GrB/private/gb_get_args.m b/GraphBLAS/@GrB/private/gb_get_args.m deleted file mode 100644 index 329223a593..0000000000 --- a/GraphBLAS/@GrB/private/gb_get_args.m +++ /dev/null @@ -1,46 +0,0 @@ -function [args, is_GrB] = gb_get_args (varargin) -%GB_GET_ARGS get arguments for a GraphBLAS method. -% Get the arguments and the descriptor for a GrB.method. Any input -% arguments that are GraphBLAS sparse matrix objects are replaced with the -% struct arg.opaque so that they can be passed to the underlying -% mexFunction. Next, the descriptor is modified to change the default -% d.kind. -% -% All mexFunctions in private/mexFunction/*.c require the descriptor to be -% present as the last argument. They are not required for the user- -% accessible GrB.methods. If the descriptor d is not present, then it is -% created and appended to the argument list, with d.kind = 'GrB'. If the -% descriptor is present and d.kind does not appear, then d.kind = 'GrB' is -% set. Finally, is_GrB is set true if d.kind is 'GrB'. If d.kind is 'GrB', -% then the underlying mexFunction returns a GraphBLAS struct, which is then -% converted above to a GraphBLAS object. - -% get the args and extract any GraphBLAS matrix structs -args = varargin ; -for k = 1:length (args) - if (isa (args {k}, 'GrB')) - args {k} = args {k}.opaque ; - end -end - -% find the descriptor -is_GrB = true ; -if (~isempty (args)) - % get the last input argument and see if it is a GraphBLAS descriptor - d = args {end} ; - if (isstruct (d) && ~isfield (d, 'GraphBLAS')) - % found the descriptor. If it does not have d.kind, add it. - if (~isfield (d, 'kind')) - d.kind = 'GrB' ; - args {end} = d ; - is_GrB = true ; - else - is_GrB = isequal (d.kind, 'GrB') || isequal (d.kind, 'default') ; - end - else - % the descriptor is not present; add it - args {end+1} = struct ('kind', 'GrB') ; - is_GrB = true ; - end -end - diff --git a/GraphBLAS/@GrB/private/gb_get_index.m b/GraphBLAS/@GrB/private/gb_get_index.m deleted file mode 100644 index b20b81d5b5..0000000000 --- a/GraphBLAS/@GrB/private/gb_get_index.m +++ /dev/null @@ -1,15 +0,0 @@ -function [I, whole] = gb_get_index (I_input) -%GB_GET_INDEX helper function for subsref and subsasgn - -whole = isequal (I_input, {':'}) & ischar (I_input {1}) ; -if (whole) - % C (:) - I = { } ; -elseif (iscell (I_input {1})) - % C ({ }), C ({ list }), C ({start,fini}), or C ({start,inc,fini}). - I = I_input {1} ; -else - % C (I) for an explicit list I, or MATLAB colon notation - I = I_input ; -end - diff --git a/GraphBLAS/@GrB/private/gb_get_pair.m b/GraphBLAS/@GrB/private/gb_get_pair.m new file mode 100644 index 0000000000..df92738d39 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_get_pair.m @@ -0,0 +1,16 @@ +function [x, y] = gb_get_pair (A) +%GB_GET_PAIR get a pair of scalars from a parameter of length 2 + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end + +type = gbtype (A) ; +desc.kind = 'full' ; +A = gbfull (A, type, 0, desc) ; +x = A (1) ; +y = A (2) ; + diff --git a/GraphBLAS/@GrB/private/gb_get_scalar.m b/GraphBLAS/@GrB/private/gb_get_scalar.m index 7604dce2c0..b038931d6f 100644 --- a/GraphBLAS/@GrB/private/gb_get_scalar.m +++ b/GraphBLAS/@GrB/private/gb_get_scalar.m @@ -1,10 +1,17 @@ function x = gb_get_scalar (A) -%GB_GET_SCALAR get the first scalar from a matrix +%GB_GET_SCALAR get a scalar from a matrix -[~, ~, x] = GrB.extracttuples (A) ; -if (isempty (x)) - x = 0 ; -else - x = x (1) ; +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end + +[m, n] = gbsize (A) ; +if (m ~= 1 || n ~= 1) + error ('input parameter %s must be a scalar', inputname (1)) ; end +x = gb_scalar (A) ; + diff --git a/GraphBLAS/@GrB/private/gb_index.m b/GraphBLAS/@GrB/private/gb_index.m new file mode 100644 index 0000000000..ea99b3558e --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_index.m @@ -0,0 +1,84 @@ +function [I, whole] = gb_index (I) +%GB_INDEX helper function for subsref and subsasgn +% [I, whole] = gb_index (I) converts I into a cell array of MATLAB +% matrices or vectors containing integer indices, to access A(I). +% +% I = { }: this denotes A(:), accessing all rows or all columns. +% In this case, the parameter whole is returned as true. +% +% I = { list }: denotes A(list) +% +% I = { start,fini }: denotes A(start:fini), without forming +% the explicit list start:fini. +% +% I = { start,inc,fini }: denotes A(start:inc:fini), without forming +% the explicit list start:inc:fini. +% +% The input I can be a GraphBLAS matrix (as an object or its opaque +% struct). In this case, it is wrapped in a cell, I = {gb_index1(I)}, +% but kept as 1-based indices (they are later translated to 0-based). +% +% If the input is already a cell array, then it is already in one of the +% above forms. Any member of the cell array that is a GraphBLAS matrix or +% struct is converted into an index list, with gb_index1(I{k}). +% +% MATLAB passes the string I = ':' to the subsref and subsasgn methods. +% This is converted into I = { }. +% +% If I is a MATLAB matrix or vector (not a cell array), then it is +% wrapped in a cell array, { I }, to denote A(I). + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +whole = false ; + +if (isobject (I)) + + % C (I) where I is a GraphBLAS matrix/vector of integer indices + I = I.opaque ; + I = { (gb_index1 (I)) } ; + +elseif (isstruct (I)) + + % C (I) where I is the opaque struct of a GrB matrix/vector + I = { (gb_index1 (I)) } ; + +elseif (iscell (I)) + + % The index I already appears as a cell, for the usage + % C ({ }), C ({ I }), C ({start,fini}), or C ({start,inc,fini}). + len = length (I) ; + if (len > 3) + error ('invalid indexing: usage is A ({start,inc,fini})') ; + elseif (len == 0) + % C ({ }) + whole = true ; + else + % C ({ I }), C ({start,fini}), or C ({start,inc,fini}) + for k = 1:length(I) + K = I {k} ; + if (isobject (K)) + % C ({ ..., K, ... }) where K is a GraphBLAS object + K = K.opaque ; + end + if (isstruct (K)) + % C ({ ..., K, ... }) where I is a GraphBLAS struct + I {k} = gb_index1 (K) ; + end + end + end + +elseif (ischar (I) && isequal (I, ':')) + + % C (:) + I = { } ; + whole = true ; + +else + + % C (I) where I is a MATLAB matrix/vector of integer indices + I = { I } ; + +end + diff --git a/GraphBLAS/@GrB/private/gb_index1.m b/GraphBLAS/@GrB/private/gb_index1.m new file mode 100644 index 0000000000..733ef077b5 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_index1.m @@ -0,0 +1,31 @@ +function I = gb_index1 (G) +%GB_INDEX1 get one GraphBLAS index for gb_index +% For C=A(I,J), or C(I,J)=A, the indices I and J must be integer lists. +% They can be passed in as GraphBLAS matrices, to subsref and subsasgn. +% This function converts them into into integer lists so that they can be +% handled by the mexFunctions. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +type = gbtype (G) ; +I = gbextractvalues (G) ; + +switch (type) + + case { 'double', 'int64', 'uint64' } + % the mexFunctions handle these three cases themselves + + case { 'single' } + % the mexFunctions check the indices later, for non-integers + I = double (I) ; + + case { 'single complex', 'double complex' } + error ('array indices must be integers') ; + + otherwise + % any other integer must be typecast to double, int64, or uint64. + % int64 is fine since any errors will be checked later. + I = int64 (I) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_isfloat.m b/GraphBLAS/@GrB/private/gb_isfloat.m new file mode 100644 index 0000000000..c4c7cee2a5 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_isfloat.m @@ -0,0 +1,9 @@ +function s = gb_isfloat (type) +%GB_ISFLOAT true for floating-point GraphBLAS types. +% Implements s = isfloat (type (G)) + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +s = contains (type, 'double') || contains (type, 'single') ; + diff --git a/GraphBLAS/@GrB/private/gb_isfull.m b/GraphBLAS/@GrB/private/gb_isfull.m new file mode 100644 index 0000000000..769fa99533 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_isfull.m @@ -0,0 +1,15 @@ +function s = gb_isfull (A) +%GB_ISFULL determine if all entries are present in a GraphBLAS struct. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[m, n] = gbsize (A) ; +if (isinteger (m)) + % gbsize returms m and n as integer if either m or n are larger + % than flintmax. In this case, A must be sparse. + s = false ; +else + s = (m*n == gbnvals (A)) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_isscalar.m b/GraphBLAS/@GrB/private/gb_isscalar.m new file mode 100644 index 0000000000..927ad7b8dc --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_isscalar.m @@ -0,0 +1,11 @@ +function s = gb_isscalar (G) +%GB_ISSCALAR determine if the GraphBLAS matrix is a scalar. +% isscalar (G) is true for an m-by-n GraphBLAS matrix if m and n are 1. +% G is an opaque GraphBLAS struct or a MATLAB matrix. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[m, n] = gbsize (G) ; +s = (m == 1) && (n == 1) ; + diff --git a/GraphBLAS/@GrB/private/gb_issigned.m b/GraphBLAS/@GrB/private/gb_issigned.m new file mode 100644 index 0000000000..6be4bd2c92 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_issigned.m @@ -0,0 +1,11 @@ +function s = gb_issigned (type) +%GB_ISSIGNED Determine if a type is signed or unsigned. +% s = gb_issigned (type) returns true if type is the string 'double', +% 'single', 'single complex', 'double complex', 'int8', 'int16', 'int32', +% or 'int64'. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +s = ~ (isequal (type, 'logical') || contains (type, 'uint')) ; + diff --git a/GraphBLAS/@GrB/private/gb_issymmetric.m b/GraphBLAS/@GrB/private/gb_issymmetric.m new file mode 100644 index 0000000000..d5d314ef0e --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_issymmetric.m @@ -0,0 +1,57 @@ +function s = gb_issymmetric (G, option, herm) +%GB_ISSYMMETRIC check if symmetric or Hermitian +% Implements issymmetric (G,option) and ishermitian (G,option). + +% FUTURE: this can be much faster; see CHOLMOD/MATLAB/spsym. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[m, n, type] = gbsize (G) ; + +if (m ~= n) + + s = false ; + +else + + if (isequal (type, 'logical')) + G = gbnew (G, 'double') ; + end + + if (herm && contains (type, 'complex')) + % T = G', complex conjugate transpose + desc.in0 = 'transpose' ; + T = gbapply ('conj', G, desc) ; + else + % T = G.', array transpose + T = gbtrans (G) ; + end + + switch (option) + + case { 'skew' } + + % G is skew symmetric/Hermitian if G+T is zero + s = (gbnorm (gb_eadd (G, '+', T), 1) == 0) ; + + case { 'nonskew' } + + % G is symmetric/Hermitian if G-T is zero + s = (gbnormdiff (G, T, 1) == 0) ; + + otherwise + + error ('invalid option') ; + + end + + clear T + + if (s) + % also check the pattern; G might have explicit zeros + S = gb_spones (G, 'logical') ; + s = gbisequal (S, gbtrans (S)) ; + end +end + diff --git a/GraphBLAS/@GrB/private/gb_isvector.m b/GraphBLAS/@GrB/private/gb_isvector.m new file mode 100644 index 0000000000..171dd6c649 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_isvector.m @@ -0,0 +1,11 @@ +function s = gb_isvector (G) +%GB_ISVECTOR determine if the GraphBLAS matrix is a row or column vector, +% where G is the opaque struct of the GraphBLAS matrix. +% gb_isvector (G) is true for an m-by-n GraphBLAS matrix if m or n is 1. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[m, n] = gbsize (G) ; +s = (m == 1) || (n == 1) ; + diff --git a/GraphBLAS/@GrB/private/gb_max1.m b/GraphBLAS/@GrB/private/gb_max1.m new file mode 100644 index 0000000000..6b487bd024 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_max1.m @@ -0,0 +1,15 @@ +function C = gb_max1 (op, A) +%GB_MAX1 single-input max +% Implements C = max (A) + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[m, n] = gbsize (A) ; +if (m == 1 || n == 1) + % C = max (A) for a vector A results in a scalar C + C = gb_maxall (op, A) ; +else + C = gb_maxbycol (op, A) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_max2.m b/GraphBLAS/@GrB/private/gb_max2.m new file mode 100644 index 0000000000..eceee11b90 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_max2.m @@ -0,0 +1,45 @@ +function C = gb_max2 (op, A, B) +%GB_MAX2 2-input max +% Implements C = max (A,B) + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[am, an, atype] = gbsize (A) ; +[bm, bn, btype] = gbsize (B) ; +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; +ctype = gboptype (atype, btype) ; + +if (a_is_scalar) + if (b_is_scalar) + % both A and B are scalars. Result is also a scalar. + C = gb_union_op (op, A, B) ; + else + % A is a scalar, B is a matrix + if (gb_scalar (A) > 0) + % since A > 0, the result is full + A = gb_scalar_to_full (bm, bn, ctype, A) ; + C = gbeadd (A, op, B) ; + else + % since A <= 0, the result is sparse. + C = gbapply2 (A, op, B) ; + end + end +else + if (b_is_scalar) + % A is a matrix, B is a scalar + if (gb_scalar (B) > 0) + % since B > 0, the result is full + B = gb_scalar_to_full (am, an, ctype, B) ; + C = gbeadd (A, op, B) ; + else + % since B <= 0, the result is sparse. + C = gbapply2 (A, op, B) ; + end + else + % both A and B are matrices. Result is sparse. + C = gb_union_op (op, A, B) ; + end +end + diff --git a/GraphBLAS/@GrB/private/gb_max3.m b/GraphBLAS/@GrB/private/gb_max3.m new file mode 100644 index 0000000000..3263d68914 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_max3.m @@ -0,0 +1,22 @@ +function C = gb_max3 (op, A, option) +%GB_MAX3 3-input max +% Implements C = max (A, [ ], option) + +if (isequal (option, 'all')) + % C = max (A, [ ] 'all'), reducing all entries to a scalar + C = gb_maxall (op, A) ; +else + option = gb_get_scalar (option) ; + if (option == 1) + % C = max (A, [ ], 1) reduces each column to a scalar, + % giving a 1-by-n row vector. + C = gb_maxbycol (op, A) ; + elseif (option == 2) + % C = max (A, [ ], 2) reduces each row to a scalar, + % giving an m-by-1 column vector. + C = gb_maxbyrow (op, A) ; + else + error ('invalid option') ; + end +end + diff --git a/GraphBLAS/@GrB/private/gb_maxall.m b/GraphBLAS/@GrB/private/gb_maxall.m new file mode 100644 index 0000000000..7a02cf7ce7 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_maxall.m @@ -0,0 +1,15 @@ +function C = gb_maxall (op, A) +%GB_MAXALL reduce a matrix to a scalar +% Implements C = max (A, [ ], 'all') ; + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +C = gbreduce (op, A) ; +[m, n] = gbsize (A) ; +if ((m*n ~= gbnvals (A)) && gb_scalar (C) <= 0) + % A is not full, and the max of the entries present is <= 0, + % so C is an empty scalar (an implicit zero) + C = gbnew (1, 1, gbtype (C)) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_maxbycol.m b/GraphBLAS/@GrB/private/gb_maxbycol.m new file mode 100644 index 0000000000..fab45f6d8f --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_maxbycol.m @@ -0,0 +1,30 @@ +function C = gb_maxbycol (op, A) +%GB_MAXBYCOL max, by column +% Implements C = max (A, [ ], 1) + +% C = max (A, [ ], 1) reduces each col to a scalar; C is 1-by-n +desc.in0 = 'transpose' ; +C = gbvreduce (op, A, desc) ; + +% if C(j) < 0, but if A(:,j) is sparse, then assign C(j) = 0. +ctype = gbtype (C) ; + +if (gb_issigned (ctype)) + % d (j) = number of entries in A(:,j); d (j) not present if A(:,j) empty + [m, n] = gbsize (A) ; + d = gbdegree (A, 'col') ; + % d (j) is an explicit zero if A(:,j) has 1 to m-1 entries + d = gbselect (d, '<', m) ; + zero = gbnew (0, ctype) ; + if (gbnvals (d) == n) + % all columns A(:,j) have between 1 and m-1 entries + C = gbapply2 (op, C, zero) ; + else + d = gbapply2 (['1st.' ctype], zero, d) ; + % if d (j) is between 1 and m-1 and C (j) < 0 then C (j) = 0 + C = gbeadd (op, C, d) ; + end +end + +C = gbtrans (C) ; + diff --git a/GraphBLAS/@GrB/private/gb_maxbyrow.m b/GraphBLAS/@GrB/private/gb_maxbyrow.m new file mode 100644 index 0000000000..ae914cc3ec --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_maxbyrow.m @@ -0,0 +1,27 @@ +function C = gb_maxbyrow (op, A) +%GB_MAXBYROW max, by row +% Implements C = max (A, [ ], 2) + +% C = max (A, [ ], 2) reduces each row to a scalar; C is m-by-1 +C = gbvreduce (op, A) ; + +% if C(i) < 0, but if A(i,:) is sparse, then assign C(i) = 0. +ctype = gbtype (C) ; + +if (gb_issigned (ctype)) + % d (i) = number of entries in A(i,:); d (i) not present if A(i,:) empty + [m, n] = gbsize (A) ; + d = gbdegree (A, 'row') ; + % d (i) is an explicit zero if A(i,:) has 1 to n-1 entries + d = gbselect (d, '<', n) ; + zero = gbnew (0, ctype) ; + if (gbnvals (d) == m) + % all rows A(i,:) have between 1 and n-1 entries + C = gbapply2 (op, C, zero) ; + else + d = gbapply2 (['1st.' ctype], zero, d) ; + % if d(i) is between 1 and n-1 and C(i) < 0 then C(i) = 0 + C = gbeadd (op, C, d) ; + end +end + diff --git a/GraphBLAS/@GrB/private/gb_min1.m b/GraphBLAS/@GrB/private/gb_min1.m new file mode 100644 index 0000000000..c47fcea902 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_min1.m @@ -0,0 +1,15 @@ +function C = gb_min1 (op, A) +%GB_MIN1 single-input min +% Implements C = min (A) + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[m, n] = gbsize (A) ; +if (m == 1 || n == 1) + % C = min (A) for a vector A results in a scalar C + C = gb_minall (op, A) ; +else + C = gb_minbycol (op, A) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_min2.m b/GraphBLAS/@GrB/private/gb_min2.m new file mode 100644 index 0000000000..56f2c02333 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_min2.m @@ -0,0 +1,45 @@ +function C = gb_min2 (op, A, B) +%GB_MIN2 2-input min +% Implements C = min (A,B) + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[am, an, atype] = gbsize (A) ; +[bm, bn, btype] = gbsize (B) ; +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; +ctype = gboptype (atype, btype) ; + +if (a_is_scalar) + if (b_is_scalar) + % both A and B are scalars. Result is also a scalar. + C = gb_union_op (op, A, B) ; + else + % A is a scalar, B is a matrix + if (gb_scalar (A) < 0) + % since A < 0, the result is full + A = gb_scalar_to_full (bm, bn, ctype, A) ; + C = gbeadd (A, op, B) ; + else + % since A >= 0, the result is sparse. + C = gbapply2 (A, op, B) ; + end + end +else + if (b_is_scalar) + % A is a matrix, B is a scalar + if (gb_scalar (B) < 0) + % since B < 0, the result is full + B = gb_scalar_to_full (am, an, ctype, B) ; + C = gbeadd (A, op, B) ; + else + % since B >= 0, the result is sparse. + C = gbapply2 (A, op, B) ; + end + else + % both A and B are matrices. Result is sparse. + C = gb_union_op (op, A, B) ; + end +end + diff --git a/GraphBLAS/@GrB/private/gb_min3.m b/GraphBLAS/@GrB/private/gb_min3.m new file mode 100644 index 0000000000..a5c8375cb8 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_min3.m @@ -0,0 +1,22 @@ +function C = gb_min3 (op, A, option) +%GB_MIN3 3-input min +% Implements C = min (A, [ ], option) + +if (isequal (option, 'all')) + % C = min (A, [ ] 'all'), reducing all entries to a scalar + C = gb_minall (op, A) ; +else + option = gb_get_scalar (option) ; + if (option == 1) + % C = min (A, [ ], 1) reduces each column to a scalar, + % giving a 1-by-n row vector. + C = gb_minbycol (op, A) ; + elseif (option == 2) + % C = min (A, [ ], 2) reduces each row to a scalar, + % giving an m-by-1 column vector. + C = gb_minbyrow (op, A) ; + else + error ('invalid option') ; + end +end + diff --git a/GraphBLAS/@GrB/private/gb_minall.m b/GraphBLAS/@GrB/private/gb_minall.m new file mode 100644 index 0000000000..28c3296ceb --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_minall.m @@ -0,0 +1,15 @@ +function C = gb_minall (op, A) +%GB_MINALL reduce a matrix to a scalar +% Implements C = min (A, [ ], 'all') ; + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +C = gbreduce (op, A) ; +[m, n] = gbsize (A) ; +if ((m*n ~= gbnvals (A)) && gb_scalar (C) >= 0) + % A is not full, and the min of the entries present is >= 0, + % so C is an empty scalar (an implicit zero) + C = gbnew (1, 1, gbtype (C)) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_minbycol.m b/GraphBLAS/@GrB/private/gb_minbycol.m new file mode 100644 index 0000000000..e86099b982 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_minbycol.m @@ -0,0 +1,28 @@ +function C = gb_minbycol (op, A) +%GB_MINBYCOL min, by column +% Implements C = min (A, [ ], 1) + +% C = min (A, [ ], 1) reduces each col to a scalar; C is 1-by-n +desc.in0 = 'transpose' ; +C = gbvreduce (op, A, desc) ; + +% if C(j) > 0, but if A(:,j) is sparse, then assign C(j) = 0. +ctype = gbtype (C) ; + + % d (j) = number of entries in A(:,j); d (j) not present if A(:,j) empty + [m, n] = gbsize (A) ; + d = gbdegree (A, 'col') ; + % d (j) is an explicit zero if A(:,j) has 1 to m-1 entries + d = gbselect (d, '<', m) ; + zero = gbnew (0, ctype) ; + if (gbnvals (d) == n) + % all columns A(:,j) have between 1 and m-1 entries + C = gbapply2 (op, C, zero) ; + else + d = gbapply2 (['1st.' ctype], zero, d) ; + % if d (j) is between 1 and m-1 and C (j) > 0 then C (j) = 0 + C = gbeadd (op, C, d) ; + end + +C = gbtrans (C) ; + diff --git a/GraphBLAS/@GrB/private/gb_minbyrow.m b/GraphBLAS/@GrB/private/gb_minbyrow.m new file mode 100644 index 0000000000..121fd746f6 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_minbyrow.m @@ -0,0 +1,25 @@ +function C = gb_minbyrow (op, A) +%GB_MINBYROW min, by row +% Implements C = min (A, [ ], 2) + +% C = min (A, [ ], 2) reduces each row to a scalar; C is m-by-1 +C = gbvreduce (op, A) ; + +% if C(i) > 0, but if A(i,:) is sparse, then assign C(i) = 0. +ctype = gbtype (C) ; + + % d (i) = number of entries in A(i,:); d (i) not present if A(i,:) empty + [m, n] = gbsize (A) ; + d = gbdegree (A, 'row') ; + % d (i) is an explicit zero if A(i,:) has 1 to n-1 entries + d = gbselect (d, '<', n) ; + zero = gbnew (0, ctype) ; + if (gbnvals (d) == m) + % all rows A(i,:) have between 1 and n-1 entries + C = gbapply2 (op, C, zero) ; + else + d = gbapply2 (['1st.' ctype], zero, d) ; + % if d(i) is between 1 and n-1 and C(i) > 0 then C (i) = 0 + C = gbeadd (op, C, d) ; + end + diff --git a/GraphBLAS/@GrB/private/gb_mpower.m b/GraphBLAS/@GrB/private/gb_mpower.m new file mode 100644 index 0000000000..20c72df3ab --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_mpower.m @@ -0,0 +1,17 @@ +function C = gb_mpower (A, b) +%GB_MPOWER C = A^b where b > 0 is an integer + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (b == 1) + C = A ; +else + T = gb_mpower (A, floor (b/2)) ; + C = gbmxm (T, '+.*', T) ; + clear T ; + if (mod (b, 2) == 1) + C = gbmxm (C, '+.*', A) ; + end +end + diff --git a/GraphBLAS/@GrB/private/gb_nnz.m b/GraphBLAS/@GrB/private/gb_nnz.m new file mode 100644 index 0000000000..8a53bbc99c --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_nnz.m @@ -0,0 +1,9 @@ +function e = gb_nnz (G) +%GB_NNZ the number of nonzeros in a GraphBLAS matrix. +% Implements e = nnz (G) + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +e = gbnvals (G) - gbnvals (gbselect (G, '==0')) ; + diff --git a/GraphBLAS/@GrB/private/gb_numel.m b/GraphBLAS/@GrB/private/gb_numel.m new file mode 100644 index 0000000000..b0ba199fb3 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_numel.m @@ -0,0 +1,14 @@ +function s = gb_numel (G) +%GB_NUMEL the maximum number of entries a GraphBLAS matrix can hold. +% Implements s = numel (G) + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[m, n] = gbsize (G) ; +s = m*n ; + +if (m > flintmax || n > flintmax || s > flintmax) + s = vpa (vpa (m, 64) * vpa (n, 64), 128) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_parse_args.m b/GraphBLAS/@GrB/private/gb_parse_args.m new file mode 100644 index 0000000000..e33a17301a --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_parse_args.m @@ -0,0 +1,43 @@ +function [m, n, type] = gb_parse_args (func, varargin) +%GB_PARSE_ARGS parse arguments for true, false, ones, zeros, eye, +% and speye. +% +% C = ones ; +% C = ones (n) ; +% C = ones (m,n) ; +% C = ones ([m n]) ; +% C = ones (... , 'like', G) ; +% C = ones (... , 'int8') ; + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +% parse the type +type = 'double' ; +nargs = length (varargin) ; +for k = 1:nargs + arg = varargin {k} ; + if (ischar (arg)) + if (isequal (arg, 'like')) + if (nargs ~= k+1) + error ('usage: %s (m, n, ''like'', G)', func) ; + end + arg = varargin {k+1} ; + if (isobject (arg)) + arg = arg.opaque ; + end + type = gbtype (arg) ; + else + if (nargs ~= k) + error ('usage: %s (m, n, type)', func) ; + end + type = arg ; + end + nargs = k-1 ; + break ; + end +end + +% parse the dimensions +[m, n] = gb_parse_dimensions (varargin {1:nargs}) ; + diff --git a/GraphBLAS/@GrB/private/gb_parse_dimensions.m b/GraphBLAS/@GrB/private/gb_parse_dimensions.m new file mode 100644 index 0000000000..1445ce3cb1 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_parse_dimensions.m @@ -0,0 +1,35 @@ +function [m, n] = gb_parse_dimensions (arg1, arg2) +%GB_GET_DIMENSIONS parse arguments for dimensions + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +switch (nargin) + + case { 0 } + + % C = GrB.eye + m = 1 ; + n = 1 ; + + case { 1 } + + if (length (arg1) == 1) + % C = ones (n) + m = gb_get_scalar (arg1) ; + n = m ; + elseif (length (arg1) == 2) + % C = ones ([m n]) + [m, n] = gb_get_pair (arg1) ; + else + error ('invalid dimensions') ; + end + + case { 2 } + + % C = ones (m, n) + m = gb_get_scalar (arg1) ; + n = gb_get_scalar (arg2) ; + +end + diff --git a/GraphBLAS/@GrB/private/gb_power.m b/GraphBLAS/@GrB/private/gb_power.m new file mode 100644 index 0000000000..9ae3248d05 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_power.m @@ -0,0 +1,98 @@ +function C = gb_power (A, B) +%GB_POWER .^ Array power. +% C = A.^B computes element-wise powers. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[am, an, atype] = gbsize (A) ; +[bm, bn, btype] = gbsize (B) ; +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; +a_is_real = ~contains (atype, 'complex') ; +b_is_real = ~contains (btype, 'complex') ; + +% determine if C = A.^B is real or complex +if (a_is_real && b_is_real) + % A and B are both real. Determine if C might be complex. + if (contains (btype, 'int') || isequal (btype, 'logical')) + % B is logical or integer, so C is real + c_is_real = true ; + elseif (gbisequal (B, gbapply ('round', B))) + % B is floating point, but all values are equal to integers + c_is_real = true ; + elseif (gb_scalar (gbreduce ('min', A)) >= 0) + % All entries in A are non-negative, so C is real + c_is_real = true ; + else + % A contains negative entries, and B is non-integer, so C can + % be complex. + c_is_real = false ; + end +else + % A or B are complex, or both, so C must be complex + c_is_real = false ; +end + +if (c_is_real) + % C is real + ctype = gboptype (atype, btype) ; +else + % C is complex + if (contains (atype, 'single') && contains (btype, 'single')) + ctype = 'single complex' ; + else + ctype = 'double complex' ; + end +end + +% B is always full +B = gbfull (B, ctype) ; + +% determine the operator +op = ['pow.' ctype] ; + +if (a_is_scalar) + + %---------------------------------------------------------------------- + % A is a scalar: C is a full matrix + %---------------------------------------------------------------------- + + C = gbapply2 (op, gbfull (A, ctype), B) ; + +else + + %---------------------------------------------------------------------- + % A is a matrix + %---------------------------------------------------------------------- + + if (b_is_scalar) + % A is a matrix, B is a scalar + b = gb_scalar (B) ; + if (b == 0) + % special case: C = A.^0 = ones (am, an, ctype) + C = gb_scalar_to_full (am, an, ctype, 1) ; + return ; + elseif (b == 1) + % special case: C = A.^1 = A + C = A ; + return + elseif (b <= 0) + % 0.^b where b < 0 is Inf, so C is full + C = gbapply2 (op, gbfull (A, ctype), B) ; + else + % The scalar b is > 0, and thus 0.^b is zero, so C is sparse. + C = gbapply2 (op, A, B) ; + end + else + % both A and B are matrices. 0.^0 is NaN, so C is full. + C = gbemult (op, gbfull (A, ctype), B) ; + end + +end + +% convert C to real if imaginary part is zero +if (~c_is_real) + C = gb_to_real_if_imag_zero (C) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_printf_helper.m b/GraphBLAS/@GrB/private/gb_printf_helper.m index 546a0b54af..06efb24440 100644 --- a/GraphBLAS/@GrB/private/gb_printf_helper.m +++ b/GraphBLAS/@GrB/private/gb_printf_helper.m @@ -1,11 +1,17 @@ function result = gb_printf_helper (printf_function, varargin) %GB_PRINTF_HELPER wrapper for fprintf and sprintf +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + % convert all GraphBLAS matrices to full MATLAB matrices -for k = 2:nargin-1 +len = length (varargin) ; +for k = 2:len arg = varargin {k} ; - if (isa (arg, 'GrB')) - varargin {k} = full (cast (full (arg), GrB.type (arg))) ; + if (isobject (arg)) + arg = arg.opaque ; + desc.kind = 'full' ; + varargin {k} = gbfull (arg, gbtype (arg), 0, desc) ; end end diff --git a/GraphBLAS/@GrB/private/gb_prod.m b/GraphBLAS/@GrB/private/gb_prod.m new file mode 100644 index 0000000000..7816198cbd --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_prod.m @@ -0,0 +1,57 @@ +function C = gb_prod (op, type, G, option) +%GB_PROD C = prod (G), using the given operator and type +% Implements C = prod (G) and C = all (G). + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[m, n] = gbsize (G) ; + +if (nargin == 3) + % C = prod (G) + if (m == 1 || n == 1) + option = 'all' ; + else + option = 1 ; + end +end + + +switch (option) + + case { 'all' } + + % C = prod (G, 'all'), reducing all entries to a scalar + if (m*n == gbnvals (G)) + C = gbreduce (op, G) ; + else + C = gbnew (0, type) ; + end + + case { 1 } + + % C = prod (G,1) reduces each column to a scalar, + % giving a 1-by-n row vector. + % M = find (column degree of G == m) + M = gbselect (gbdegree (G, 'col'), '==', m) ; + Cin = gbnew (n, 1, type) ; + % C = op (G') + desc.in0 = 'transpose' ; + C = gbtrans (gbvreduce (Cin, M, op, G, desc)) ; + + case { 2 } + + % C = prod (G,2) reduces each row to a scalar, + % giving an m-by-1 column vector. + % M = find (row degree of G == n) + M = gbselect (gbdegree (G, 'row'), '==', n) ; + % C = op (G) + Cin = gbnew (m, 1, type) ; + C = gbvreduce (Cin, M, op, G) ; + + otherwise + + error ('unknown option') ; +end + + diff --git a/GraphBLAS/@GrB/private/gb_random.m b/GraphBLAS/@GrB/private/gb_random.m new file mode 100644 index 0000000000..10ff6dcac5 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_random.m @@ -0,0 +1,170 @@ +function C = gb_random (varargin) +%GB_RANDOM uniformly distributed random GraphBLAS matrix. +% Implements C = GrB.random (...), C = sprand (...), C = sprand (...), + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +%--------------------------------------------------------------------------- +% parse inputs +%--------------------------------------------------------------------------- + +% defaults +dist = 'uniform' ; +type = 'double' ; +range = [ ] ; +sym_option = 'unsymmetric' ; +firstchar = nargin + 1 ; + +% look for strings +for k = 1:nargin + arg = varargin {k} ; + if (ischar (arg)) + arg = lower (arg) ; + firstchar = min (firstchar, k) ; + switch arg + case { 'uniform', 'normal' } + dist = arg ; + case { 'range' } + range = varargin {k+1} ; + if (isobject (range)) + range = range.opaque ; + end + [rm, rn, type] = gbsize (range) ; + if (rm*rn > 2) + error ('range must contain at most 2 entries') ; + end + range = gbfull (range, type, 0, struct ('kind', 'full')) ; + case { 'unsymmetric', 'symmetric', 'hermitian' } + sym_option = arg ; + otherwise + error ('unknown option') ; + end + end +end + +symmetric = isequal (sym_option, 'symmetric') ; +hermitian = isequal (sym_option, 'hermitian') ; +desc.base = 'zero-based' ; + +%--------------------------------------------------------------------------- +% construct the pattern +%--------------------------------------------------------------------------- + +if (firstchar == 2) + + % C = GrB.random (A, ...) ; + A = varargin {1} ; + if (isobject (A)) + A = A.opaque ; + end + [m, n] = gbsize (A) ; + if ((symmetric || hermitian) && (m ~= n)) + error ('input matrix must be square') ; + end + [I, J] = gbextracttuples (A, desc) ; + e = length (I) ; + +elseif (firstchar == (4 - (symmetric || hermitian))) + + % C = GrB.random (m, n, d, ...) + % C = GrB.random (n, d, ... 'symmetric') + % C = GrB.random (n, d, ... 'hermitian') + m = gb_get_scalar (varargin {1}) ; + if (symmetric || hermitian) + n = m ; + d = gb_get_scalar (varargin {2}) ; + else + n = gb_get_scalar (varargin {2}) ; + d = gb_get_scalar (varargin {3}) ; + end + if (isinf (d)) + % construct a dense random matrix + e = m * n ; + I = repmat ((int64 (0) : int64 (m-1)), 1, n) ; + J = repmat ((int64 (0) : int64 (n-1)), m, 1) ; + else + % construct a sparse random matrix with about e entries + e = round (m * n * d) ; + I = int64 (floor (rand (e, 1) * m)) ; + J = int64 (floor (rand (e, 1) * n)) ; + end + +else + + error ('invalid usage') ; + +end + +%--------------------------------------------------------------------------- +% construct the values +%--------------------------------------------------------------------------- + +if (isequal (type, 'logical')) + + % X is logical: just pass a single logical 'true' to GrB.build + X = true ; + +else + + % construct the initial random values + if (isequal (dist, 'uniform')) + X = rand (e, 1) ; + else + X = randn (e, 1) ; + end + + % scale the values and typecast if requested + if (~isempty (range)) + lo = double (min (range)) ; + hi = double (max (range)) ; + if (contains (type, 'int')) + % X is signed or unsigned integer + X = cast (floor ((hi - lo + 1) * X + lo), type) ; + elseif (~contains (type, 'complex')) + % X is single or double real + X = cast ((hi - lo) * X + lo, type) ; + else + % X is complex: construct random imaginary values + if (isequal (dist, 'uniform')) + Y = rand (e, 1) ; + else + Y = randn (e, 1) ; + end + X = (hi - lo) * X + lo ; + Y = (hi - lo) * Y + lo ; + if (isequal (type, 'single complex')) + % X is single complex + X = single (X) ; + Y = single (Y) ; + end + X = complex (X, Y) ; + end + end + +end + +%--------------------------------------------------------------------------- +% build the matrix +%--------------------------------------------------------------------------- + +C = gbbuild (I, J, X, m, n, '2nd', desc) ; + +% make it symmetric or hermitian, if requested +L = gbselect ('tril', C, -1) ; +if (symmetric) + % C = tril (C) + tril (C,-1)' + C = gbeadd (gbselect ('tril', C, 0), '+', gbtrans (L)) ; +elseif (hermitian) + % C = L + L' + real (diag (C)) + LT = gbtrans (L) ; + if (contains (gbtype (LT), 'complex')) + LT = gbapply ('conj', LT) ; + end + D = gbselect ('diag', C, 0) ; + if (contains (gbtype (D), 'complex')) + D = gbapply ('creal', D) ; + end + C = gbeadd (L, '+', gbeadd (LT, '+', D)) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_scalar.m b/GraphBLAS/@GrB/private/gb_scalar.m new file mode 100644 index 0000000000..df81a92a12 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_scalar.m @@ -0,0 +1,17 @@ +function x = gb_scalar (A) +%GB_SCALAR get contents of a scalar +% x = gb_scalar (A). A may be a MATLAB scalar or a GraphBLAS +% scalar as a struct (not an object). Returns the result x +% as a MATLAB non-sparse scalar. If the scalar has no entry +% (the MATLAB sparse(0)), then x is returned as zero. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +[~, ~, x] = gbextracttuples (A) ; +if (isempty (x)) + x = 0 ; +else + x = x (1) ; +end + diff --git a/GraphBLAS/@GrB/private/gb_scalar_to_full.m b/GraphBLAS/@GrB/private/gb_scalar_to_full.m new file mode 100644 index 0000000000..aaefcc38f3 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_scalar_to_full.m @@ -0,0 +1,4 @@ +function C = gb_scalar_to_full (m, n, type, scalar) +%GB_DENSE expand a scalar into a dense matrix + +C = gbsubassign (gbnew (m, n, type), gbfull (scalar)) ; diff --git a/GraphBLAS/@GrB/private/gb_sparse_comparator.m b/GraphBLAS/@GrB/private/gb_sparse_comparator.m deleted file mode 100644 index 2c387e58ca..0000000000 --- a/GraphBLAS/@GrB/private/gb_sparse_comparator.m +++ /dev/null @@ -1,19 +0,0 @@ -function C = gb_sparse_comparator (A, op, B) -%GB_SPARSE_COMPARATOR compare two sparse matrices. -% The pattern of C is the set union of A and B. A and B must first be -% expanded to include explicit zeros in the set union of A and B. For -% example, with A < B for two matrices A and B: -% -% in A in B A(i,j) < B (i,j) true or false -% not in A in B 0 < B(i,j) true or false -% in A not in B A(i,j) < 0 true or false -% not in A not in B 0 < 0 false, not in C -% -% expand A and B to the set union of A and B, with explicit zeros. -% The type of the '1st' operator is the type of the first argument of -% GrB.eadd, so the 2nd argument can be boolean to save space. - -A0 = GrB.eadd ('1st', A, GrB.expand (false, B)) ; -B0 = GrB.eadd ('1st', B, GrB.expand (false, A)) ; -C = GrB.eadd (A0, op, B0) ; - diff --git a/GraphBLAS/@GrB/private/gb_speye.m b/GraphBLAS/@GrB/private/gb_speye.m new file mode 100644 index 0000000000..5ddce29022 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_speye.m @@ -0,0 +1,27 @@ +function C = gb_speye (func, varargin) +%GB_SPEYE Sparse identity matrix, of any type supported by GraphBLAS. +% Implements C = GrB.eye (...) and GrB.speye (...). + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +% get the size and type +[m, n, type] = gb_parse_args (func, varargin {:}) ; + +% construct the m-by-n identity matrix of the given type +m = max (m, 0) ; +n = max (n, 0) ; +mn = min (m, n) ; +I = int64 (0) : int64 (mn-1) ; +desc.base = 'zero-based' ; + +if (isequal (type, 'single complex')) + X = complex (ones (mn, 1, 'single')) ; +elseif (contains (type, 'complex')) + X = complex (ones (mn, 1, 'double')) ; +else + X = ones (mn, 1, type) ; +end + +C = gbbuild (I, I, X, m, n, '1st', type, desc) ; + diff --git a/GraphBLAS/@GrB/private/gb_spones.m b/GraphBLAS/@GrB/private/gb_spones.m new file mode 100644 index 0000000000..c7c607e690 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_spones.m @@ -0,0 +1,25 @@ +function C = gb_spones (G, type) +%GB_SPONES return pattern of GraphBLAS matrix. +% Implements C = spones (G). + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (nargin == 1) + switch (gbtype (G)) + case { 'single complex' } + op = '1.single' ; + case { 'double complex' } + op = '1.double' ; + otherwise + op = '1' ; + end +else + if (~ischar (type)) + error ('type must be a string') ; + end + op = ['1.' type] ; +end + +C = gbapply (op, G) ; + diff --git a/GraphBLAS/@GrB/private/gb_sum.m b/GraphBLAS/@GrB/private/gb_sum.m new file mode 100644 index 0000000000..f99de4f615 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_sum.m @@ -0,0 +1,40 @@ +function C = gb_sum (op, G, option) +%GB_SUM C = sum (G) or C = any (G) + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (nargin == 2) + % C = sum (G) + if (gb_isvector (G)) + option = 'all' ; + else + option = 1 ; + end +end + +switch (option) + + case { 'all' } + + % C = sum (G, 'all'), reducing all entries to a scalar + C = gbreduce (op, G) ; + + case { 1 } + + % C = sum (G, 1) reduces each column to a scalar, + % giving a 1-by-n row vector. + desc.in0 = 'transpose' ; + C = gbtrans (gbvreduce (op, G, desc)) ; + + case { 2 } + + % C = sum (G, 2) reduces each row to a scalar, + % giving an m-by-1 column vector. + C = gbvreduce (op, G) ; + + otherwise + + error ('unknown option') ; +end + diff --git a/GraphBLAS/@GrB/private/gb_to_real_if_imag_zero.m b/GraphBLAS/@GrB/private/gb_to_real_if_imag_zero.m new file mode 100644 index 0000000000..c9598ccb8e --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_to_real_if_imag_zero.m @@ -0,0 +1,13 @@ +function C = gb_to_real_if_imag_zero (G) +%GB_TO_REAL_IF_IMAG_ZERO convert complex matrix to real if imag(G) is zero + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. +% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. + +if (contains (gbtype (G), 'complex') && ... + gbnvals (gbselect ('nonzero', gbapply ('cimag', G))) == 0) + C = gbapply ('creal', G) ; +else + C = G ; +end + diff --git a/GraphBLAS/@GrB/private/gb_trig.m b/GraphBLAS/@GrB/private/gb_trig.m new file mode 100644 index 0000000000..ed331f7121 --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_trig.m @@ -0,0 +1,65 @@ +function C = gb_trig (op, G) +%GB_TRIG inverse sine, cosine, log, sqrt, ... etc +% Implements C = asin (G), C = acos (G), C = atanh (G), ... etc + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +type = gbtype (G) ; + +% determine if any entries are outside the domain for the real case +switch (op) + + case { 'asin', 'acos', 'atanh' } + + % C is complex if any (abs (G) > 1) + switch (type) + case { 'int8', 'int16', 'int32', 'int64', 'single', 'double' } + noutside = gbnvals (gbselect (gbapply ('abs', G), '>', 1)) ; + case { 'uint8', 'uint16', 'uint32', 'uint64' } + noutside = gbnvals (gbselect (G, '>', 1)) ; + otherwise + noutside = 0 ; + end + + case { 'log', 'log10', 'sqrt', 'log2' } + + % C is complex if any (G < 0) + switch (type) + case { 'int8', 'int16', 'int32', 'int64', 'single', 'double' } + noutside = gbnvals (gbselect (G, '<', 0)) ; + otherwise + noutside = 0 ; + end + + case { 'log1p' } + + % C is complex if any (G < -1) + switch (type) + case { 'int8', 'int16', 'int32', 'int64', 'single', 'double' } + noutside = gbnvals (gbselect (G, '<', -1)) ; + otherwise + noutside = 0 ; + end + + case { 'acosh' } + + % C is complex if any (G < 1) + noutside = gbnvals (gbselect (G, '<', 1)) ; + +end + +if (noutside > 0) + % G is real but C is complex + if (isequal (type, 'single')) + op = [op '.single complex'] ; + else + op = [op '.double complex'] ; + end +elseif (~gb_isfloat (type)) + % G is integer or logical; use the op.double operator + op = [op '.double'] ; +end + +C = gbapply (op, G) ; + diff --git a/GraphBLAS/@GrB/private/gb_union_op.m b/GraphBLAS/@GrB/private/gb_union_op.m new file mode 100644 index 0000000000..51795882db --- /dev/null +++ b/GraphBLAS/@GrB/private/gb_union_op.m @@ -0,0 +1,60 @@ +function C = gb_union_op (op, A, B) +%GB_SPARSE_BINOP apply a binary operator to two sparse matrices. +% The pattern of C is the set union of A and B. A and B must first be +% expanded to include explicit zeros in the set union of A and B. For +% example, with A < B for two matrices A and B: +% +% in A in B A(i,j) < B (i,j) true or false +% not in A in B 0 < B(i,j) true or false +% in A not in B A(i,j) < 0 true or false +% not in A not in B 0 < 0 false, not in C +% +% A and B are expanded to the set union of A and B, with explicit zeros, +% and then the op is applied via GrB.emult. Unlike the built-in +% GraphBLAS GrB.eadd and GrB.emult, both of which apply the operator +% only to the set intersection, this function applies the operator to the +% set union of A and B. +% +% The inputs are MATLAB matrices or GraphBLAS structs. The output +% is a GraphBLAS struct. +% +% See also GrB/lt, GrB/min, GrB/max, GrB/ne, GrB/pow2, GrB/atan2, +% GrB/bitset, GrB/complex. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +% FUTURE: this is slower than it could be. +% affects: lt, gt, min(A,B), max(A,B), minus, ne, pow2, atan2, bitset, complex, +% hypot, and bitshift. +% +% This would be faster if a variant to GrB_eWiseAdd would be added, which takes +% 2 scalar values (one for A and one for B), and applies the binary operator on +% the union of A and B. +% +% The following operations could use this feature: +% +% lt, gt, min, max, ne, pow2, atan2, bitset: (0, 0) +% bitshift: (0, (int8) 0) +% minus: (0, 0), using the '-' operator instead of A+(-B) +% complex: (0, 0) +% hypot: (0, 0), uses abs (gb_eadd (...)) +% +% Suppose the variant is GrB_eWiseUnion (... A, ascalar, B, bscalar). +% If a scalar is NULL, it would be treated as eWiseAdd, with +% f(aij,NULL) = aij (the 'first' operator), and f(NULL,bij)=bij, +% the 'second' operator. So if both are passed in as NULL, +% GrB_eWiseUnion (... A, NULL, B, NULL, ...) is identical to +% GrB_eWiseAdd (... A, B...). + +type = gboptype (gbtype (A), gbtype (B)) ; + +% A0 = expand A by padding it with zeros from the pattern of B +A0 = gbeadd (['1st.' type], A, gb_expand (0, B, type)) ; + +% B0 = expand B by padding it with zeros from the pattern of A +B0 = gbeadd (['1st.' type], B, gb_expand (0, A, type)) ; + +% A0 and B0 now have the same pattern, so gbemult can be used: +C = gbemult (A0, op, B0) ; + diff --git a/GraphBLAS/@GrB/private/gbapply.m b/GraphBLAS/@GrB/private/gbapply.m index ee314da82c..e83934ddef 100644 --- a/GraphBLAS/@GrB/private/gbapply.m +++ b/GraphBLAS/@GrB/private/gbapply.m @@ -1,4 +1,4 @@ -function Cout = gbapply (Cin, M, accum, op, A, desc) %#ok +function C = gbapply (Cin, M, accum, op, A, desc) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/gbassign.m b/GraphBLAS/@GrB/private/gbassign.m index 64269582c8..91181929f9 100644 --- a/GraphBLAS/@GrB/private/gbassign.m +++ b/GraphBLAS/@GrB/private/gbassign.m @@ -1,4 +1,4 @@ -function Cout = gbassign (Cin, M, accum, A, I, J, desc) %#ok +function C = gbassign (Cin, M, accum, A, I, J, desc) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/gbeadd.m b/GraphBLAS/@GrB/private/gbeadd.m index 46642eee2e..42991972e3 100644 --- a/GraphBLAS/@GrB/private/gbeadd.m +++ b/GraphBLAS/@GrB/private/gbeadd.m @@ -1,4 +1,4 @@ -function Cout = gbeadd (Cin, M, accum, semiring, A, B, desc) %#ok +function C = gbeadd (Cin, M, accum, semiring, A, B, desc) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/gbemult.m b/GraphBLAS/@GrB/private/gbemult.m index bb882f0570..2cb0ed8deb 100644 --- a/GraphBLAS/@GrB/private/gbemult.m +++ b/GraphBLAS/@GrB/private/gbemult.m @@ -1,4 +1,4 @@ -function Cout = gbemult (Cin, M, accum, semiring, A, B, desc) %#ok +function C = gbemult (Cin, M, accum, semiring, A, B, desc) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/gbextract.m b/GraphBLAS/@GrB/private/gbextract.m index 6ce0e113d1..c152a426b8 100644 --- a/GraphBLAS/@GrB/private/gbextract.m +++ b/GraphBLAS/@GrB/private/gbextract.m @@ -1,4 +1,4 @@ -function Cout = gbextract (Cin, M, accum, A, I, J, desc) %#ok +function C = gbextract (Cin, M, accum, A, I, J, desc) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/gbkronecker.m b/GraphBLAS/@GrB/private/gbkronecker.m index 232919040a..0429c91eba 100644 --- a/GraphBLAS/@GrB/private/gbkronecker.m +++ b/GraphBLAS/@GrB/private/gbkronecker.m @@ -1,4 +1,4 @@ -function Cout = gbkronecker (Cin, M, accum, op, A, B, desc) %#ok +function C = gbkronecker (Cin, M, accum, op, A, B, desc) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/gblogassign.m b/GraphBLAS/@GrB/private/gblogassign.m index 680d8a63f2..32e84b48be 100644 --- a/GraphBLAS/@GrB/private/gblogassign.m +++ b/GraphBLAS/@GrB/private/gblogassign.m @@ -1,4 +1,4 @@ -function Cout = gblogassign (Cin, M, A) %#ok +function C = gblogassign (Cin, M, A) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/gbmake.m b/GraphBLAS/@GrB/private/gbmake.m index 882b74b601..5780ecc609 100644 --- a/GraphBLAS/@GrB/private/gbmake.m +++ b/GraphBLAS/@GrB/private/gbmake.m @@ -18,13 +18,13 @@ function gbmake (what) % GraphBLAS, just as GrB.clear does. It then calls GrB.init to initialize % GraphBLAS. % -% See also: mex, version, GrB.clear +% See also mex, version, GrB.clear. % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. if verLessThan ('matlab', '9.4') - gb_error ('MATLAB 9.4 (R2018a) or later is required') ; + error ('MATLAB 9.4 (R2018a) or later is required') ; end % finish GraphBLAS @@ -147,7 +147,8 @@ function gbmake (what) % compile the cfile if it is newer than its object file, or any hfile if (make_all || tc > tobj || htime > tobj) % compile the cfile - fprintf ('%s\n', cfile) ; + % fprintf ('%s\n', cfile) ; + fprintf ('.') ; mexcmd = sprintf ('mex -c %s -silent %s ''%s''', flags, inc, cfile) ; eval (mexcmd) ; any_c_compiled = true ; @@ -179,11 +180,14 @@ function gbmake (what) % compile the mexFunction mexcmd = sprintf ('mex %s -silent %s %s ''%s'' %s -lgraphblas', ... ldflags, flags, inc, mexfunction, objlist) ; - fprintf ('%s\n', mexcmd) ; + % fprintf ('%s\n', mexcmd) ; + fprintf (':') ; eval (mexcmd) ; end end +fprintf ('\n') ; + % start GraphBLAS try GrB.init @@ -191,17 +195,25 @@ function gbmake (what) end fprintf ('Compilation of the MATLAB interface to GraphBLAS is complete.\n') ; -fprintf ('Add the following commands to your startup.m file:\n') ; -cd ../.. -fprintf ('\n addpath (''%s'') ;\n', pwd) ; -cd .. +fprintf ('Add the following commands to your startup.m file:\n\n') ; +here1 = cd ('../..') ; +addpath (pwd) ; +fprintf (' addpath (''%s'') ;\n', pwd) ; +cd ('..') ; if ispc - fprintf (' addpath (''%s/build/Release'') ;\n', pwd) ; + lib_path = sprintf ('%s/build/Release', pwd) ; else - fprintf (' addpath (''%s/build'') ;\n', pwd) ; + lib_path = sprintf ('%s/build', pwd) ; end +fprintf (' addpath (''%s'') ;\n', lib_path) ; +addpath (lib_path) ; +cd (here1) ; + +fprintf ('\nFor a quick demo of GraphBLAS, type the following commands:\n\n') ; +fprintf (' cd ../../demo\n') ; +fprintf (' gbdemo\n') ; fprintf ('\nTo test GraphBLAS, type the following commands:\n\n') ; -fprintf (' cd GraphBLAS/test\n') ; +fprintf (' cd ../../test\n') ; fprintf (' gbtest\n') ; diff --git a/GraphBLAS/@GrB/private/gbmxm.m b/GraphBLAS/@GrB/private/gbmxm.m index 7fefaa451f..ec5b7c0978 100644 --- a/GraphBLAS/@GrB/private/gbmxm.m +++ b/GraphBLAS/@GrB/private/gbmxm.m @@ -1,4 +1,4 @@ -function Cout = gbmxm (Cin, M, accum, semiring, A, B, desc) %#ok +function C = gbmxm (Cin, M, accum, semiring, A, B, desc) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/gbreduce.m b/GraphBLAS/@GrB/private/gbreduce.m index 115097af3d..eb0094b981 100644 --- a/GraphBLAS/@GrB/private/gbreduce.m +++ b/GraphBLAS/@GrB/private/gbreduce.m @@ -1,4 +1,4 @@ -function cout = gbreduce (cin, accum, op, A, desc) %#ok +function c = gbreduce (cin, accum, op, A, desc) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/gbselect.m b/GraphBLAS/@GrB/private/gbselect.m index 06fd8d2c95..d0b2b6797f 100644 --- a/GraphBLAS/@GrB/private/gbselect.m +++ b/GraphBLAS/@GrB/private/gbselect.m @@ -1,4 +1,4 @@ -function Cout = gbselect (Cin, M, accum, op, A, b, desc) %#ok +function C = gbselect (Cin, M, accum, op, A, b, desc) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/gbsize.m b/GraphBLAS/@GrB/private/gbsize.m index d111dc260b..be2ed59039 100644 --- a/GraphBLAS/@GrB/private/gbsize.m +++ b/GraphBLAS/@GrB/private/gbsize.m @@ -1,7 +1,7 @@ -function [m, n] = gbsize (G) %#ok +function [m, n, type] = gbsize (G, dim) %#ok -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com See GraphBLAS/Doc/License.txt. error ('GrB:mex', 'mexFunction not found; use gbmake to compile GraphBLAS') ; diff --git a/GraphBLAS/@GrB/private/gbsubassign.m b/GraphBLAS/@GrB/private/gbsubassign.m index 70ddd58882..a2fdbb2b19 100644 --- a/GraphBLAS/@GrB/private/gbsubassign.m +++ b/GraphBLAS/@GrB/private/gbsubassign.m @@ -1,4 +1,4 @@ -function Cout = gbsubassign (Cin, M, accum, A, I, j, desc) %#ok +function C = gbsubassign (Cin, M, accum, A, I, j, desc) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/gbtrans.m b/GraphBLAS/@GrB/private/gbtrans.m index 7bbda483d2..177fd6c2f5 100644 --- a/GraphBLAS/@GrB/private/gbtrans.m +++ b/GraphBLAS/@GrB/private/gbtrans.m @@ -1,4 +1,4 @@ -function Cout = gbtrans (Cin, M, accum, A, desc) %#ok +function C = gbtrans (Cin, M, accum, A, desc) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/gbvreduce.m b/GraphBLAS/@GrB/private/gbvreduce.m index 16ac4d3d1a..b5a5bba6ed 100644 --- a/GraphBLAS/@GrB/private/gbvreduce.m +++ b/GraphBLAS/@GrB/private/gbvreduce.m @@ -1,4 +1,4 @@ -function Cout = gbvreduce (Cin, M, accum, op, A, desc) %#ok +function C = gbvreduce (Cin, M, accum, op, A, desc) %#ok % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbapply.c b/GraphBLAS/@GrB/private/mexfunctions/gbapply.c index c7e2d28ebb..11eb4b4859 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbapply.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbapply.c @@ -11,17 +11,18 @@ // Usage: -// Cout = GrB.apply (op, A, desc) -// Cout = GrB.apply (Cin, accum, op, A, desc) -// Cout = GrB.apply (Cin, M, op, A, desc) -// Cout = GrB.apply (Cin, M, accum, op, A, desc) +// C = gbapply (unop, A) +// C = gbapply (unop, A, desc) +// C = gbapply (Cin, accum, unop, A, desc) +// C = gbapply (Cin, M, unop, A, desc) +// C = gbapply (Cin, M, accum, unop, A, desc) // If Cin is not present then it is implicitly a matrix with no entries, of the // right size (which depends on A, B, and the descriptor). #include "gb_matlab.h" -#define USAGE "usage: Cout = GrB.apply (Cin, M, accum, op, A, desc)" +#define USAGE "usage: C = GrB.apply (Cin, M, accum, op, A, desc)" void mexFunction ( @@ -36,8 +37,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage ((nargin == 3 || nargin == 5 || nargin == 6) && nargout <= 1, - USAGE) ; + gb_usage (nargin >= 2 && nargin <= 6 && nargout <= 2, USAGE) ; //-------------------------------------------------------------------------- // find the arguments @@ -93,14 +93,14 @@ void mexFunction if (nstrings == 1) { - op = gb_mxstring_to_unop (String [0], atype) ; + op = gb_mxstring_to_unop (String [0], atype) ; } else { // if accum appears, then Cin must also appear CHECK_ERROR (C == NULL, USAGE) ; - accum = gb_mxstring_to_binop (String [0], ctype) ; - op = gb_mxstring_to_unop (String [1], atype) ; + accum = gb_mxstring_to_binop (String [0], ctype, ctype) ; + op = gb_mxstring_to_unop (String [1], atype) ; } //-------------------------------------------------------------------------- @@ -154,6 +154,7 @@ void mexFunction //-------------------------------------------------------------------------- pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbapply2.c b/GraphBLAS/@GrB/private/mexfunctions/gbapply2.c new file mode 100644 index 0000000000..6689a7e378 --- /dev/null +++ b/GraphBLAS/@GrB/private/mexfunctions/gbapply2.c @@ -0,0 +1,232 @@ +//------------------------------------------------------------------------------ +// gbapply2: apply a binary operator to a matrix, with scalaring binding +//------------------------------------------------------------------------------ + +// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. +// http://suitesparse.com See GraphBLAS/Doc/License.txt for license. + +//------------------------------------------------------------------------------ + +// gbapply2 is an interface to GxB_Matrix_apply_BinaryOp1st. +// and GxB_Matrix_apply_Binaryop2nd. + +// Usage: + +// C = gbapply2 (binop, A, B) +// C = gbapply2 (binop, A, B, desc) +// C = gbapply2 (Cin, accum, binop, A, B, desc) +// C = gbapply2 (Cin, M, binop, A, B, desc) +// C = gbapply2 (Cin, M, accum, binop, A, B, desc) + +// Either A or B (or both) must be a scalar (1-by-1, with 0 or 1 entries). +// If the scalar has no entry, it is treated as the value zero. + +// If Cin is not present then it is implicitly a matrix with no entries, of the +// right size (which depends on A, B, and the descriptor). + +#include "gb_matlab.h" + +#define USAGE "usage: C = GrB.apply2 (Cin, M, accum, binop, A, B, desc)" + +void mexFunction +( + int nargout, + mxArray *pargout [ ], + int nargin, + const mxArray *pargin [ ] +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + gb_usage (nargin >= 3 && nargin <= 7 && nargout <= 2, USAGE) ; + + //-------------------------------------------------------------------------- + // find the arguments + //-------------------------------------------------------------------------- + + mxArray *Matrix [4], *String [2], *Cell [2] ; + base_enum_t base ; + kind_enum_t kind ; + GxB_Format_Value fmt ; + int nmatrices, nstrings, ncells ; + GrB_Descriptor desc ; + gb_get_mxargs (nargin, pargin, USAGE, Matrix, &nmatrices, String, &nstrings, + Cell, &ncells, &desc, &base, &kind, &fmt) ; + + CHECK_ERROR (nmatrices < 2 || nstrings < 1 || ncells > 0, USAGE) ; + + //-------------------------------------------------------------------------- + // get the matrices + //-------------------------------------------------------------------------- + + GrB_Type atype, btype, ctype = NULL ; + GrB_Matrix C = NULL, M = NULL, A, B ; + + if (nmatrices == 2) + { + A = gb_get_shallow (Matrix [0]) ; + B = gb_get_shallow (Matrix [1]) ; + } + else if (nmatrices == 3) + { + C = gb_get_deep (Matrix [0]) ; + A = gb_get_shallow (Matrix [1]) ; + B = gb_get_shallow (Matrix [2]) ; + } + else // if (nmatrices == 4) + { + C = gb_get_deep (Matrix [0]) ; + M = gb_get_shallow (Matrix [1]) ; + A = gb_get_shallow (Matrix [2]) ; + B = gb_get_shallow (Matrix [3]) ; + } + + OK (GxB_Matrix_type (&atype, A)) ; + OK (GxB_Matrix_type (&btype, B)) ; + if (C != NULL) + { + OK (GxB_Matrix_type (&ctype, C)) ; + } + + //-------------------------------------------------------------------------- + // determine which input is the scalar and which is the matrix + //-------------------------------------------------------------------------- + + GrB_Index anrows, ancols, bnrows, bncols ; + + // get the size of A and B + OK (GrB_Matrix_nrows (&anrows, A)) ; + OK (GrB_Matrix_ncols (&ancols, A)) ; + OK (GrB_Matrix_nrows (&bnrows, B)) ; + OK (GrB_Matrix_ncols (&bncols, B)) ; + + GxB_Scalar scalar, scalar0 = NULL ; + bool binop_bind1st ; + if (anrows == 1 && ancols == 1) + { + // A is the scalar and B is the matrix + binop_bind1st = true ; + scalar = (GxB_Scalar) A ; // NOTE: this is not allowed by the spec + } + else if (bnrows == 1 && bncols == 1) + { + // A is the matrix and B is the scalar + binop_bind1st = false ; + scalar = (GxB_Scalar) B ; // NOTE: this is not allowed by the spec + } + else + { + ERROR ("either A or B must be a scalar") ; + } + + //-------------------------------------------------------------------------- + // make sure the scalar has one entry + //-------------------------------------------------------------------------- + + GrB_Index nvals ; + OK (GxB_Scalar_nvals (&nvals, scalar)) ; + if (nvals == 0) + { + // GxB_apply requires at least one entry. Create a new scalar zero. + OK (GxB_Scalar_dup (&scalar0, scalar)) ; + // the scalar need not be int32; this will typecast as needed + OK (GxB_Scalar_setElement_INT32 (scalar0, 0)) ; + OK (GxB_Scalar_wait (&scalar0)) ; + scalar = scalar0 ; + } + + //-------------------------------------------------------------------------- + // get the operators + //-------------------------------------------------------------------------- + + GrB_BinaryOp accum = NULL, op = NULL ; + + if (nstrings == 1) + { + op = gb_mxstring_to_binop (String [0], atype, btype) ; + } + else + { + // if accum appears, then Cin must also appear + CHECK_ERROR (C == NULL, USAGE) ; + accum = gb_mxstring_to_binop (String [0], ctype, ctype) ; + op = gb_mxstring_to_binop (String [1], atype, btype) ; + } + + //-------------------------------------------------------------------------- + // construct C if not present on input + //-------------------------------------------------------------------------- + + // If C is NULL, then it is not present on input. + // Construct C of the right size and type. + + if (C == NULL) + { + // get the descriptor to determine if the input matrix is transposed + GrB_Index cnrows, cncols ; + if (binop_bind1st) + { + // A is the scalar and B is the matrix + GrB_Desc_Value in1 ; + OK (GxB_Desc_get (desc, GrB_INP0, &in1)) ; + bool B_transpose = (in1 == GrB_TRAN) ; + // determine the size of C + cnrows = (B_transpose) ? bncols : bnrows ; + cncols = (B_transpose) ? bnrows : bncols ; + } + else + { + // A is the matrix and B is the scalar + GrB_Desc_Value in0 ; + OK (GxB_Desc_get (desc, GrB_INP0, &in0)) ; + bool A_transpose = (in0 == GrB_TRAN) ; + // determine the size of C + cnrows = (A_transpose) ? ancols : anrows ; + cncols = (A_transpose) ? anrows : ancols ; + } + + // use the ztype of the op as the type of C + OK (GxB_BinaryOp_ztype (&ctype, op)) ; + + OK (GrB_Matrix_new (&C, ctype, cnrows, cncols)) ; + fmt = gb_get_format (cnrows, cncols, A, B, fmt) ; + OK (GxB_Matrix_Option_set (C, GxB_FORMAT, fmt)) ; + } + + //-------------------------------------------------------------------------- + // compute C += op (A,B) where one input is a scalar + //-------------------------------------------------------------------------- + + if (binop_bind1st) + { + // printf ("bind 1st:\n") ; + OK (GxB_Matrix_apply_BinaryOp1st (C, M, accum, op, scalar, B, desc)) ; + } + else + { + // printf ("bind 2nd:\n") ; + OK (GxB_Matrix_apply_BinaryOp2nd (C, M, accum, op, A, scalar, desc)) ; + } + + //-------------------------------------------------------------------------- + // free shallow copies + //-------------------------------------------------------------------------- + + OK (GrB_Matrix_free (&M)) ; + OK (GrB_Matrix_free (&A)) ; + OK (GrB_Matrix_free (&B)) ; + OK (GrB_Matrix_free (&scalar0)) ; + OK (GrB_Descriptor_free (&desc)) ; + + //-------------------------------------------------------------------------- + // export the output matrix C back to MATLAB + //-------------------------------------------------------------------------- + + pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; + GB_WRAPUP ; +} + diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbassign.c b/GraphBLAS/@GrB/private/mexfunctions/gbassign.c index c59760c8a2..dc82dabac2 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbassign.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbassign.c @@ -16,9 +16,9 @@ // Usage: -// Cout = gbassign (Cin, M, accum, A, I, J, desc) +// C = gbassign (Cin, M, accum, A, I, J, desc) -// Cin, A, and desc are required. See GrB.m for more details. +// Cin and A required. See GrB.m for more details. #include "gb_matlab.h" @@ -31,6 +31,6 @@ void mexFunction ) { gb_assign (nargout, pargout, nargin, pargin, false, - "usage: Cout = GrB.assign (Cin, M, accum, A, I, J, desc)") ; + "usage: C = GrB.assign (Cin, M, accum, A, I, J, desc)") ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbbinopinfo.c b/GraphBLAS/@GrB/private/mexfunctions/gbbinopinfo.c index 61f6d1f5ed..3eca952ff5 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbbinopinfo.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbbinopinfo.c @@ -27,7 +27,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin <= 2 && nargout == 0, + gb_usage (nargin >= 1 && nargin <= 2 && nargout == 0, "usage: GrB.binopinfo (binop) or GrB.binopinfo (binop,type)") ; //-------------------------------------------------------------------------- @@ -39,13 +39,13 @@ void mexFunction gb_mxstring_to_string (opstring, LEN, pargin [0], "binary operator") ; GrB_Type type = NULL ; - if (nargin == 2) + if (nargin > 1) { type = gb_mxstring_to_type (pargin [1]) ; CHECK_ERROR (type == NULL, "unknown type") ; } - GrB_BinaryOp op = gb_mxstring_to_binop (pargin [0], type) ; + GrB_BinaryOp op = gb_mxstring_to_binop (pargin [0], type, type) ; OK (GxB_BinaryOp_fprint (op, opstring, GxB_COMPLETE, NULL)) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbbuild.c b/GraphBLAS/@GrB/private/mexfunctions/gbbuild.c index 24b7fefb27..2ac53025c8 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbbuild.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbbuild.c @@ -9,6 +9,7 @@ // Usage: +// A = gbbuild (I, J, X) // A = gbbuild (I, J, X, desc) // A = gbbuild (I, J, X, m, desc) // A = gbbuild (I, J, X, m, n, desc) @@ -16,11 +17,16 @@ // A = gbbuild (I, J, X, m, n, dup, type, desc) ; // m and n default to the largest index in I and J, respectively. -// dup defaults to 'plus.xtype' where xtype is the type of X. + +// dup is a string that defaults to 'plus.xtype' where xtype is the type of X. // If dup is given by without a type, type of dup defaults to the type of X. -// type is the type of A, which defaults to the type of X. -// desc.kind is the only part used from the descriptor. +// type is a string that defines is the type of A, which defaults to the type +// of X. + +// The descriptor is optional; if present, it must be the last input parameter. +// desc.kind is the only part used from the descriptor, and it defaults to +// desc.kind = 'GrB'. #include "gb_matlab.h" @@ -37,8 +43,8 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin >= 4 && nargin <= 8 && nargout <= 1, - "usage: A = GrB.build (I, J, X, m, n, dup, type)") ; + gb_usage (nargin >= 3 && nargin <= 8 && nargout <= 2, + "usage: A = GrB.build (I, J, X, m, n, dup, type, desc)") ; //-------------------------------------------------------------------------- // get the descriptor @@ -47,13 +53,13 @@ void mexFunction base_enum_t base ; kind_enum_t kind ; GxB_Format_Value fmt ; - GrB_Descriptor desc = - gb_mxarray_to_descriptor (pargin [nargin-1], &kind, &fmt, &base) ; + GrB_Descriptor desc = NULL ; + desc = gb_mxarray_to_descriptor (pargin [nargin-1], &kind, &fmt, &base) ; - OK (GrB_Descriptor_free (&desc)) ; + // if present, remove the descriptor from consideration + if (desc != NULL) nargin-- ; - // remove the descriptor from consideration - nargin-- ; + OK (GrB_Descriptor_free (&desc)) ; //-------------------------------------------------------------------------- // get I and J @@ -64,10 +70,10 @@ void mexFunction int64_t Imax = -1, Jmax = -1 ; GrB_Index *I = (GrB_Index *) gb_mxarray_to_list (pargin [0], base, - &I_allocated, &ni, &Imax) ; + &I_allocated, (int64_t *) &ni, &Imax) ; GrB_Index *J = (GrB_Index *) gb_mxarray_to_list (pargin [1], base, - &J_allocated, &nj, &Jmax) ; + &J_allocated, (int64_t *) &nj, &Jmax) ; //-------------------------------------------------------------------------- // get X @@ -101,7 +107,8 @@ void mexFunction if (ni == 1 && ni < nvals) { GrB_Index *I2 = (GrB_Index *) mxMalloc (nvals * sizeof (GrB_Index)) ; - GB_matlab_helper8 (I2, I, nvals, sizeof (GrB_Index)) ; + GB_matlab_helper8 ((GB_void *) I2, (GB_void *) I, nvals, + sizeof (GrB_Index)) ; if (I_allocated) gb_mxfree (&I) ; I_allocated = true ; I = I2 ; @@ -110,7 +117,8 @@ void mexFunction if (nj == 1 && nj < nvals) { GrB_Index *J2 = (GrB_Index *) mxMalloc (nvals * sizeof (GrB_Index)) ; - GB_matlab_helper8 (J2, J, nvals, sizeof (GrB_Index)) ; + GB_matlab_helper8 ((GB_void *) J2, (GB_void *) J, nvals, + sizeof (GrB_Index)) ; if (J_allocated) gb_mxfree (&J) ; J_allocated = true ; J = J2 ; @@ -172,7 +180,7 @@ void mexFunction GrB_BinaryOp dup = NULL ; if (nargin > 5) { - dup = gb_mxstring_to_binop (pargin [5], xtype) ; + dup = gb_mxstring_to_binop (pargin [5], xtype, xtype) ; } // if dup is NULL, defaults to plus.xtype, below. @@ -208,12 +216,13 @@ void mexFunction if (xtype == GrB_BOOL) { bool empty = 0 ; - bool *X = (nvals == 0) ? &empty : mxGetData (pargin [2]) ; + bool *X = (nvals == 0) ? &empty : mxGetData (pargin [2]) ; // OK:bool if (dup == NULL) dup = GrB_LOR ; if (expandx) { X2 = mxMalloc (nvals * sizeof (bool)) ; - GB_matlab_helper8 (X2, X, nvals, sizeof (bool)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (bool)) ; X = (bool *) X2 ; } OK (GrB_Matrix_build_BOOL (A, I, J, X, nvals, dup)) ; @@ -226,7 +235,8 @@ void mexFunction if (expandx) { X2 = mxMalloc (nvals * sizeof (int8_t)) ; - GB_matlab_helper8 (X2, X, nvals, sizeof (int8_t)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (int8_t)) ; X = (int8_t *) X2 ; } OK (GrB_Matrix_build_INT8 (A, I, J, X, nvals, dup)) ; @@ -239,7 +249,8 @@ void mexFunction if (expandx) { X2 = mxMalloc (nvals * sizeof (int16_t)) ; - GB_matlab_helper8 (X2, X, nvals, sizeof (int16_t)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (int16_t)) ; X = (int16_t *) X2 ; } OK (GrB_Matrix_build_INT16 (A, I, J, X, nvals, dup)) ; @@ -252,7 +263,8 @@ void mexFunction if (expandx) { X2 = mxMalloc (nvals * sizeof (int32_t)) ; - GB_matlab_helper8 (X2, X, nvals, sizeof (int32_t)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (int32_t)) ; X = (int32_t *) X2 ; } OK (GrB_Matrix_build_INT32 (A, I, J, X, nvals, dup)) ; @@ -265,7 +277,8 @@ void mexFunction if (expandx) { X2 = mxMalloc (nvals * sizeof (int64_t)) ; - GB_matlab_helper8 (X2, X, nvals, sizeof (int64_t)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (int64_t)) ; X = (int64_t *) X2 ; } OK (GrB_Matrix_build_INT64 (A, I, J, X, nvals, dup)) ; @@ -278,7 +291,8 @@ void mexFunction if (expandx) { X2 = mxMalloc (nvals * sizeof (uint8_t)) ; - GB_matlab_helper8 (X2, X, nvals, sizeof (uint8_t)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (uint8_t)) ; X = (uint8_t *) X2 ; } OK (GrB_Matrix_build_UINT8 (A, I, J, X, nvals, dup)) ; @@ -291,7 +305,8 @@ void mexFunction if (expandx) { X2 = mxMalloc (nvals * sizeof (uint16_t)) ; - GB_matlab_helper8 (X2, X, nvals, sizeof (uint16_t)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (uint16_t)) ; X = (uint16_t *) X2 ; } OK (GrB_Matrix_build_UINT16 (A, I, J, X, nvals, dup)) ; @@ -304,7 +319,8 @@ void mexFunction if (expandx) { X2 = mxMalloc (nvals * sizeof (uint32_t)) ; - GB_matlab_helper8 (X2, X, nvals, sizeof (uint32_t)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (uint32_t)) ; X = (uint32_t *) X2 ; } OK (GrB_Matrix_build_UINT32 (A, I, J, X, nvals, dup)) ; @@ -317,7 +333,8 @@ void mexFunction if (expandx) { X2 = mxMalloc (nvals * sizeof (uint64_t)) ; - GB_matlab_helper8 (X2, X, nvals, sizeof (uint64_t)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (uint64_t)) ; X = (uint64_t *) X2 ; } OK (GrB_Matrix_build_UINT64 (A, I, J, X, nvals, dup)) ; @@ -330,7 +347,8 @@ void mexFunction if (expandx) { X2 = mxMalloc (nvals * sizeof (float)) ; - GB_matlab_helper8 (X2, X, nvals, sizeof (float)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (float)) ; X = (float *) X2 ; } OK (GrB_Matrix_build_FP32 (A, I, J, X, nvals, dup)) ; @@ -343,26 +361,42 @@ void mexFunction if (expandx) { X2 = mxMalloc (nvals * sizeof (double)) ; - GB_matlab_helper8 (X2, X, nvals, sizeof (double)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (double)) ; X = (double *) X2 ; } OK (GrB_Matrix_build_FP64 (A, I, J, X, nvals, dup)) ; } - #ifdef GB_COMPLEX_TYPE - else if (xtype == gb_complex_type) - { - double empty = 0 ; - double *X = (nvals == 0) ? &empty : mxGetComplexDoubles (pargin [2]) ; - if (dup == NULL) dup = ... ; + else if (xtype == GxB_FC32) + { + GxB_FC32_t empty = GxB_CMPLXF (0,0) ; + GxB_FC32_t *X = &empty ; + if (nvals > 0) X = (GxB_FC32_t *) mxGetComplexSingles (pargin [2]) ; + if (dup == NULL) dup = GxB_PLUS_FC32 ; if (expandx) - { - X2 = mxMalloc (nvals * sizeof (double complex)) ; - GB_matlab_helper8 (X2, X, nvals, sizeof (double complex)) ; - X = (double complex *) X2 ; + { + X2 = mxMalloc (nvals * sizeof (GxB_FC32_t)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (GxB_FC32_t)) ; + X = (GxB_FC32_t *) X2 ; + } + OK (GxB_Matrix_build_FC32 (A, I, J, X, nvals, dup)) ; + } + else if (xtype == GxB_FC64) + { + GxB_FC64_t empty = GxB_CMPLX (0,0) ; + GxB_FC64_t *X = &empty ; + if (nvals > 0) X = (GxB_FC64_t *) mxGetComplexDoubles (pargin [2]) ; + if (dup == NULL) dup = GxB_PLUS_FC64 ; + if (expandx) + { + X2 = mxMalloc (nvals * sizeof (GxB_FC64_t)) ; + GB_matlab_helper8 ((GB_void *) X2, (GB_void *) X, nvals, + sizeof (GxB_FC64_t)) ; + X = (GxB_FC64_t *) X2 ; } - OK (GrB_Matrix_build_UDT (A, I, J, X, nvals, dup)) ; + OK (GxB_Matrix_build_FC64 (A, I, J, X, nvals, dup)) ; } - #endif else { ERROR ("unsupported type") ; @@ -381,6 +415,7 @@ void mexFunction //-------------------------------------------------------------------------- pargout [0] = gb_export (&A, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbburble.c b/GraphBLAS/@GrB/private/mexfunctions/gbburble.c index 0dd6410180..fbce31fb53 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbburble.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbburble.c @@ -7,6 +7,11 @@ //------------------------------------------------------------------------------ +// Usage + +// b = gbburble ; +// b = gbburble (b) ; + #include "gb_matlab.h" void mexFunction @@ -35,17 +40,17 @@ void mexFunction { // set the burble if (gb_mxarray_is_scalar (pargin [0])) - { + { // argument is a numeric scalar b = (bool) mxGetScalar (pargin [0]) ; } else if (mxIsLogicalScalar (pargin [0])) - { + { // argument is a logical scalar b = (bool) mxIsLogicalScalarTrue (pargin [0]) ; } else - { + { ERROR ("input must be a scalar") ; } OK (GxB_Global_Option_set (GxB_BURBLE, b)) ; diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbchunk.c b/GraphBLAS/@GrB/private/mexfunctions/gbchunk.c index 2f6354a155..3667311473 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbchunk.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbchunk.c @@ -7,6 +7,11 @@ //------------------------------------------------------------------------------ +// Usage: + +// chunk = gbchunk ; +// chunk = gbchunk (chunk) ; + #include "gb_matlab.h" void mexFunction diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbdegree.c b/GraphBLAS/@GrB/private/mexfunctions/gbdegree.c index 47c929c6c8..d77ec374ea 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbdegree.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbdegree.c @@ -10,9 +10,18 @@ // The input may be either a GraphBLAS matrix struct or a standard MATLAB // sparse matrix. +// gbdegree (X, 'row') row degree +// gbdegree (X, 'col') column degree +// gbdegree (X, true) native (get degree of each vector): +// row degree if X is held by row, +// col degree if X is held by col. +// gbdegree (X, false) non-native (sum across vectors): +// col degree if X is held by row, +// row degree if X is held by col. + #include "gb_matlab.h" -#define USAGE "usage: degree = gbdegree (X, native)" +#define USAGE "usage: degree = gbdegree (X, dim)" void mexFunction ( @@ -34,7 +43,28 @@ void mexFunction //-------------------------------------------------------------------------- GrB_Matrix X = gb_get_shallow (pargin [0]) ; - bool native = (mxGetScalar (pargin [1]) != 0) ; + GxB_Format_Value fmt ; + OK (GxB_Matrix_Option_get (X, GxB_FORMAT, &fmt)) ; + + bool native ; + if (mxIsChar (pargin [1])) + { + #define LEN 256 + char dim_string [LEN+2] ; + gb_mxstring_to_string (dim_string, LEN, pargin [1], "dim") ; + if (MATCH (dim_string, "row")) + { + native = (fmt == GxB_BY_ROW) ; + } + else // if (MATCH (dim_string, "col")) + { + native = (fmt == GxB_BY_COL) ; + } + } + else + { + native = (mxGetScalar (pargin [1]) != 0) ; + } //-------------------------------------------------------------------------- // get the degree of each row or column of X @@ -45,7 +75,7 @@ void mexFunction GrB_Vector d = NULL ; if (native) - { + { //---------------------------------------------------------------------- // get the degree of each vector of X @@ -70,8 +100,6 @@ void mexFunction OK (GrB_Matrix_nvals (&nvals, X)) ; OK (GrB_Matrix_nrows (&nrows, X)) ; OK (GrB_Matrix_ncols (&ncols, X)) ; - GxB_Format_Value fmt ; - OK (GxB_Matrix_Option_get (X, GxB_FORMAT, &fmt)) ; GrB_Vector y = NULL ; if (fmt == GxB_BY_COL) @@ -82,7 +110,7 @@ void mexFunction //------------------------------------------------------------------ if (nvals < ncols / 16 && ncols > 256) - { + { // X is hypersparse, or might as well be, so let y be the // pattern of nonempty columns of X. if (!GB_matlab_helper9 (X, °ree, &list, &nvec)) @@ -93,7 +121,7 @@ void mexFunction &list, °ree, NULL)) ; } else - { + { // y = dense vector of size ncols-by-1; value is not relevant OK (GrB_Vector_new (&y, GrB_BOOL, ncols)) ; OK (GrB_Vector_assign_BOOL (y, NULL, NULL, false, GrB_ALL, @@ -113,7 +141,7 @@ void mexFunction //------------------------------------------------------------------ if (nvals < nrows / 16 && nrows > 256) - { + { // X is hypersparse, or might as well be, so let y be the // pattern of nonempty rows of X. if (!GB_matlab_helper9 (X, °ree, &list, &nvec)) @@ -124,7 +152,7 @@ void mexFunction &list, °ree, NULL)) ; } else - { + { // y = dense vector of size nrows-by-1; value is not relevant OK (GrB_Vector_new (&y, GrB_BOOL, nrows)) ; OK (GrB_Vector_assign_BOOL (y, NULL, NULL, false, GrB_ALL, diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbdescriptorinfo.c b/GraphBLAS/@GrB/private/mexfunctions/gbdescriptorinfo.c index bfa8830d50..5c67b9f415 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbdescriptorinfo.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbdescriptorinfo.c @@ -7,6 +7,11 @@ //------------------------------------------------------------------------------ +// Usage: + +// gbdescriptorinfo +// gbdescriptorinfo (desc) + #include "gb_matlab.h" void mexFunction @@ -23,7 +28,7 @@ void mexFunction //-------------------------------------------------------------------------- gb_usage (nargin <= 1 && nargout == 0, - "usage: GrB.descriptorinfo or GrB.descriptorinfo (d)") ; + "usage: GrB.descriptorinfo or GrB.descriptorinfo (desc)") ; //-------------------------------------------------------------------------- // construct the GraphBLAS descriptor @@ -32,20 +37,23 @@ void mexFunction base_enum_t base = BASE_DEFAULT ; kind_enum_t kind = KIND_GRB ; GxB_Format_Value fmt = GxB_NO_FORMAT ; - GrB_Descriptor d = (nargin == 0) ? NULL : - gb_mxarray_to_descriptor (pargin [nargin-1], &kind, &fmt, &base) ; + GrB_Descriptor desc = NULL ; + if (nargin > 0) + { + desc = gb_mxarray_to_descriptor (pargin [nargin-1], &kind, &fmt, &base); + } - if (d == NULL) + if (desc == NULL) { printf ("\nDefault GraphBLAS descriptor:\n") ; - OK (GrB_Descriptor_new (&d)) ; + OK (GrB_Descriptor_new (&desc)) ; } //-------------------------------------------------------------------------- // print the GraphBLAS descriptor //-------------------------------------------------------------------------- - OK (GxB_Descriptor_fprint (d, "", GxB_COMPLETE, NULL)) ; + OK (GxB_Descriptor_fprint (desc, "", GxB_COMPLETE, NULL)) ; //-------------------------------------------------------------------------- // print the extra terms in the MATLAB interface descriptor @@ -83,7 +91,7 @@ void mexFunction // free the descriptor //-------------------------------------------------------------------------- - OK (GrB_Descriptor_free (&d)) ; + OK (GrB_Descriptor_free (&desc)) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbdisp.c b/GraphBLAS/@GrB/private/mexfunctions/gbdisp.c index bc7b450ab5..b31b89789b 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbdisp.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbdisp.c @@ -7,6 +7,10 @@ //------------------------------------------------------------------------------ +// Usage: + +// gbdisp (C, cnz, level) + #include "gb_matlab.h" void mexFunction @@ -22,7 +26,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin == 3 && nargout == 0, "usage: gbdisp (C,cnz,level)") ; + gb_usage (nargin == 3 && nargout == 0, "usage: gbdisp (C, cnz, level)") ; //-------------------------------------------------------------------------- // get cnz and level @@ -34,15 +38,15 @@ void mexFunction #define LEN 256 char s [LEN+1] ; if (cnz == 0) - { + { snprintf (s, LEN, "no nonzeros") ; } else if (cnz == 1) - { + { snprintf (s, LEN, "1 nonzero") ; } else - { + { snprintf (s, LEN, GBd " nonzeros", cnz) ; } @@ -52,6 +56,9 @@ void mexFunction // print the GraphBLAS matrix //-------------------------------------------------------------------------- + // print 1-based indices + GB_Global_print_one_based_set (true) ; + GrB_Matrix C = gb_get_shallow (pargin [0]) ; OK (GxB_Matrix_fprint (C, s, level, NULL)) ; OK (GrB_Matrix_free (&C)) ; diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbeadd.c b/GraphBLAS/@GrB/private/mexfunctions/gbeadd.c index 4d63ba3d75..da30404e68 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbeadd.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbeadd.c @@ -7,21 +7,23 @@ //------------------------------------------------------------------------------ -// gbeadd is an interface to GrB_eWiseAdd_Matrix_*. +// gbeadd is an interface to GrB_Matrix_eWiseAdd_BinaryOp. +// Note that gbeadd and gbemult are nearly identical mexFunctions. // Usage: -// Cout = GrB.eadd (op, A, B, desc) -// Cout = GrB.eadd (Cin, accum, op, A, B, desc) -// Cout = GrB.eadd (Cin, M, op, A, B, desc) -// Cout = GrB.eadd (Cin, M, accum, op, A, B, desc) +// C = gbeadd (binop, A, B) +// C = gbeadd (binop, A, B, desc) +// C = gbeadd (Cin, accum, binop, A, B, desc) +// C = gbeadd (Cin, M, binop, A, B, desc) +// C = gbeadd (Cin, M, accum, binop, A, B, desc) -// If Cin is not present then it is implicitly a matrix with no entries, of -// the right size (which depends on A, B, and the descriptor). +// If Cin is not present then it is implicitly a matrix with no entries, of the +// right size (which depends on A, B, and the descriptor). #include "gb_matlab.h" -#define USAGE "usage: Cout = GrB.eadd (Cin, M, accum, op, A, B, desc)" +#define USAGE "usage: C = GrB.eadd (Cin, M, accum, binop, A, B, desc)" void mexFunction ( @@ -36,8 +38,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage ((nargin == 4 || nargin == 6 || nargin == 7) && nargout <= 1, - USAGE) ; + gb_usage (nargin >= 3 && nargin <= 7 && nargout <= 2, USAGE) ; //-------------------------------------------------------------------------- // find the arguments @@ -58,7 +59,7 @@ void mexFunction // get the matrices //-------------------------------------------------------------------------- - GrB_Type atype, ctype = NULL ; + GrB_Type atype, btype, ctype = NULL ; GrB_Matrix C = NULL, M = NULL, A, B ; if (nmatrices == 2) @@ -81,6 +82,7 @@ void mexFunction } OK (GxB_Matrix_type (&atype, A)) ; + OK (GxB_Matrix_type (&btype, B)) ; if (C != NULL) { OK (GxB_Matrix_type (&ctype, C)) ; @@ -94,14 +96,14 @@ void mexFunction if (nstrings == 1) { - op = gb_mxstring_to_binop (String [0], atype) ; + op = gb_mxstring_to_binop (String [0], atype, btype) ; } else { // if accum appears, then Cin must also appear CHECK_ERROR (C == NULL, USAGE) ; - accum = gb_mxstring_to_binop (String [0], ctype) ; - op = gb_mxstring_to_binop (String [1], atype) ; + accum = gb_mxstring_to_binop (String [0], ctype, ctype) ; + op = gb_mxstring_to_binop (String [1], atype, btype) ; } //-------------------------------------------------------------------------- @@ -139,7 +141,7 @@ void mexFunction // compute C += A+B //-------------------------------------------------------------------------- - OK (GrB_eWiseAdd_Matrix_BinaryOp (C, M, accum, op, A, B, desc)) ; + OK (GrB_Matrix_eWiseAdd_BinaryOp (C, M, accum, op, A, B, desc)) ; //-------------------------------------------------------------------------- // free shallow copies @@ -155,6 +157,7 @@ void mexFunction //-------------------------------------------------------------------------- pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbemult.c b/GraphBLAS/@GrB/private/mexfunctions/gbemult.c index 05553a79bc..326dd645a1 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbemult.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbemult.c @@ -7,21 +7,23 @@ //------------------------------------------------------------------------------ -// gbemult is an interface to GrB_eWiseMult_Matrix_*. +// gbemult is an interface to GrB_Matrix_eWiseMult_BinaryOp. +// Note that gbeadd and gbemult are nearly identical mexFunctions. // Usage: -// Cout = GrB.emult (op, A, B, desc) -// Cout = GrB.emult (Cin, accum, op, A, B, desc) -// Cout = GrB.emult (Cin, M, op, A, B, desc) -// Cout = GrB.emult (Cin, M, accum, op, A, B, desc) +// C = gbemult (binop, A, B) +// C = gbemult (binop, A, B, desc) +// C = gbemult (Cin, accum, binop, A, B, desc) +// C = gbemult (Cin, M, binop, A, B, desc) +// C = gbemult (Cin, M, accum, binop, A, B, desc) // If Cin is not present then it is implicitly a matrix with no entries, of the // right size (which depends on A, B, and the descriptor). #include "gb_matlab.h" -#define USAGE "usage: Cout = GrB.emult (Cin, M, accum, op, A, B, desc)" +#define USAGE "usage: C = GrB.emult (Cin, M, accum, binop, A, B, desc)" void mexFunction ( @@ -36,8 +38,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage ((nargin == 4 || nargin == 6 || nargin == 7) && nargout <= 1, - USAGE) ; + gb_usage (nargin >= 3 && nargin <= 7 && nargout <= 2, USAGE) ; //-------------------------------------------------------------------------- // find the arguments @@ -58,7 +59,7 @@ void mexFunction // get the matrices //-------------------------------------------------------------------------- - GrB_Type atype, ctype = NULL ; + GrB_Type atype, btype, ctype = NULL ; GrB_Matrix C = NULL, M = NULL, A, B ; if (nmatrices == 2) @@ -81,6 +82,7 @@ void mexFunction } OK (GxB_Matrix_type (&atype, A)) ; + OK (GxB_Matrix_type (&btype, B)) ; if (C != NULL) { OK (GxB_Matrix_type (&ctype, C)) ; @@ -94,14 +96,14 @@ void mexFunction if (nstrings == 1) { - op = gb_mxstring_to_binop (String [0], atype) ; + op = gb_mxstring_to_binop (String [0], atype, btype) ; } else { // if accum appears, then Cin must also appear CHECK_ERROR (C == NULL, USAGE) ; - accum = gb_mxstring_to_binop (String [0], ctype) ; - op = gb_mxstring_to_binop (String [1], atype) ; + accum = gb_mxstring_to_binop (String [0], ctype, ctype) ; + op = gb_mxstring_to_binop (String [1], atype, btype) ; } //-------------------------------------------------------------------------- @@ -139,7 +141,7 @@ void mexFunction // compute C += (A.*B) //-------------------------------------------------------------------------- - OK (GrB_eWiseMult_Matrix_BinaryOp (C, M, accum, op, A, B, desc)) ; + OK (GrB_Matrix_eWiseMult_BinaryOp (C, M, accum, op, A, B, desc)) ; //-------------------------------------------------------------------------- // free shallow copies @@ -155,6 +157,7 @@ void mexFunction //-------------------------------------------------------------------------- pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbextract.c b/GraphBLAS/@GrB/private/mexfunctions/gbextract.c index 337d2825fa..a31b198a72 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbextract.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbextract.c @@ -15,15 +15,15 @@ // Usage: -// Cout = gbextract (Cin, M, accum, A, I, J, desc) +// C = gbextract (Cin, M, accum, A, I, J, desc) -// A and desc are required. See GrB.m for more details. +// A is required. See GrB.m for more details. // If accum or M is used, then Cin must appear. #include "gb_matlab.h" #include "GB_ij.h" -#define USAGE "usage: Cout = GrB.extract (Cin, M, accum, A, I, J, desc)" +#define USAGE "usage: C = GrB.extract (Cin, M, accum, A, I, J, desc)" void mexFunction ( @@ -38,7 +38,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin >= 2 && nargin <= 7 && nargout <= 1, USAGE) ; + gb_usage (nargin >= 1 && nargin <= 7 && nargout <= 2, USAGE) ; //-------------------------------------------------------------------------- // find the arguments @@ -94,7 +94,7 @@ void mexFunction { // if accum appears, then Cin must also appear CHECK_ERROR (C == NULL, USAGE) ; - accum = gb_mxstring_to_binop (String [0], ctype) ; + accum = gb_mxstring_to_binop (String [0], ctype, ctype) ; } //-------------------------------------------------------------------------- @@ -156,8 +156,8 @@ void mexFunction int I_kind, J_kind ; int64_t I_colon [3], J_colon [3] ; GrB_Index cnrows, cncols ; - GB_ijlength (I, ni, anrows, &cnrows, &I_kind, I_colon) ; - GB_ijlength (J, nj, ancols, &cncols, &J_kind, J_colon) ; + GB_ijlength (I, ni, anrows, (int64_t *) &cnrows, &I_kind, I_colon) ; + GB_ijlength (J, nj, ancols, (int64_t *) &cncols, &J_kind, J_colon) ; ctype = atype ; OK (GrB_Matrix_new (&C, ctype, cnrows, cncols)) ; @@ -186,6 +186,7 @@ void mexFunction //-------------------------------------------------------------------------- pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbextracttuples.c b/GraphBLAS/@GrB/private/mexfunctions/gbextracttuples.c index 7baad3d83a..a1693ddb9a 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbextracttuples.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbextracttuples.c @@ -9,8 +9,11 @@ // Usage: +// [I J X] = GrB.extracttuples (A) // [I J X] = GrB.extracttuples (A, desc) +// The desciptor is optional. If present, it must be a struct. + // desc.base = 'zero-based': I and J are returned as 0-based int64 indices // desc.base = 'one-based int': I and J are returned as 1-based int64 indices // desc.base = 'one-based': I and J are returned as 1-based double indices @@ -40,12 +43,12 @@ void mexFunction //-------------------------------------------------------------------------- base_enum_t base = BASE_DEFAULT ; - kind_enum_t kind = KIND_GRB ; - GxB_Format_Value fmt = GxB_NO_FORMAT ; + kind_enum_t kind = KIND_FULL ; // ignored + GxB_Format_Value fmt = GxB_NO_FORMAT ; // ignored GrB_Descriptor desc = NULL ; - if (nargin == 2) + if (nargin > 1) { - desc = gb_mxarray_to_descriptor (pargin [1], &kind, &fmt, &base) ; + desc = gb_mxarray_to_descriptor (pargin [nargin-1], &kind, &fmt, &base); } OK (GrB_Descriptor_free (&desc)) ; @@ -178,17 +181,24 @@ void mexFunction pargout [2] = gb_export_to_mxfull (&X, nvals, 1, GrB_FP64) ; } } - #ifdef GB_COMPLEX_TYPE - else if (xtype == gb_complex_type) + else if (xtype == GxB_FC32) { - double *X = extract_X ? mxMalloc (s * sizeof (double complex)) : NULL ; - OK (GrB_Matrix_extractTuples_UDT (I, J, X, &nvals, A)) ; + GxB_FC32_t *X = extract_X ? mxMalloc (s * sizeof (GxB_FC32_t)) : NULL ; + OK (GxB_Matrix_extractTuples_FC32 (I, J, X, &nvals, A)) ; if (extract_X) - { - pargout [2] = gb_export_to_mxfull (&X, nvals, 1, gb_complex_type) ; + { + pargout [2] = gb_export_to_mxfull (&X, nvals, 1, GxB_FC32) ; + } + } + else if (xtype == GxB_FC64) + { + GxB_FC64_t *X = extract_X ? mxMalloc (s * sizeof (GxB_FC64_t)) : NULL ; + OK (GxB_Matrix_extractTuples_FC64 (I, J, X, &nvals, A)) ; + if (extract_X) + { + pargout [2] = gb_export_to_mxfull (&X, nvals, 1, GxB_FC64) ; } } - #endif else { ERROR ("unsupported type") ; @@ -204,12 +214,12 @@ void mexFunction OK (GrB_Matrix_nrows (&nrows, A)) ; OK (GrB_Matrix_ncols (&ncols, A)) ; if (MAX (nrows, ncols) > FLINTMAX) - { + { // the matrix is too large for I and J to be returned as double base = BASE_1_INT64 ; } else - { + { // this is the typical case base = BASE_1_DOUBLE ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbextractvalues.c b/GraphBLAS/@GrB/private/mexfunctions/gbextractvalues.c index f60ab705c8..3d34812c21 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbextractvalues.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbextractvalues.c @@ -9,7 +9,7 @@ // Usage: -// X = GrB.extractvalues (A) +// X = gbextractvalues (A) #include "gb_matlab.h" @@ -97,6 +97,7 @@ void mexFunction OK (GrB_Matrix_extractTuples_UINT64 (NULL, NULL, X, &nvals, A)) ; pargout [0] = gb_export_to_mxfull (&X, nvals, 1, GrB_UINT64) ; } + else if (xtype == GrB_FP32) { float *X = mxMalloc (s * sizeof (float)) ; @@ -109,14 +110,18 @@ void mexFunction OK (GrB_Matrix_extractTuples_FP64 (NULL, NULL, X, &nvals, A)) ; pargout [0] = gb_export_to_mxfull (&X, nvals, 1, GrB_FP64) ; } - #ifdef GB_COMPLEX_TYPE - else if (xtype == gb_complex_type) - { - double *X = mxMalloc (s * sizeof (double complex)) ; - OK (GrB_Matrix_extractTuples_UDT (NULL, NULL, X, &nvals, A)) ; - pargout [0] = gb_export_to_mxfull (&X, nvals, 1, gb_complex_type) ; + else if (xtype == GxB_FC32) + { + GxB_FC32_t *X = mxMalloc (s * sizeof (GxB_FC32_t)) ; + OK (GxB_Matrix_extractTuples_FC32 (NULL, NULL, X, &nvals, A)) ; + pargout [0] = gb_export_to_mxfull (&X, nvals, 1, GxB_FC32) ; + } + else if (xtype == GxB_FC64) + { + GxB_FC64_t *X = mxMalloc (s * sizeof (GxB_FC64_t)) ; + OK (GxB_Matrix_extractTuples_FC64 (NULL, NULL, X, &nvals, A)) ; + pargout [0] = gb_export_to_mxfull (&X, nvals, 1, GxB_FC64) ; } - #endif else { ERROR ("unsupported type") ; diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbformat.c b/GraphBLAS/@GrB/private/mexfunctions/gbformat.c index 8e0e04d3fb..1eed9723b6 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbformat.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbformat.c @@ -7,6 +7,11 @@ //------------------------------------------------------------------------------ +// Usage + +// f = gbformat ; +// f = gbformat (f) ; + #include "gb_matlab.h" void mexFunction @@ -65,9 +70,11 @@ void mexFunction //------------------------------------------------------------------ // get the format of the input matrix G - GrB_Matrix G = gb_get_shallow (pargin [0]) ; - OK (GxB_Matrix_Option_get (G, GxB_FORMAT, &fmt)) ; - OK (GrB_Matrix_free (&G)) ; + mxArray *opaque = mxGetField (pargin [0], 0, "s") ; + CHECK_ERROR (opaque == NULL, "invalid GraphBLAS struct") ; + int64_t *s = mxGetInt64s (opaque) ; + bool is_csc = (bool) (s [6]) ; + fmt = (is_csc) ? GxB_BY_COL : GxB_BY_ROW ; } } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbfull.c b/GraphBLAS/@GrB/private/mexfunctions/gbfull.c index b2af610413..5e16915d6a 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbfull.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbfull.c @@ -8,7 +8,16 @@ //------------------------------------------------------------------------------ // The input may be either a GraphBLAS matrix struct or a standard MATLAB -// sparse or dense matrix. The output is a standard MATLAB dense matrix. +// sparse or dense matrix. The output is a GraphBLAS matrix by default, with +// all entries present, of the given type. Entries are filled in with the id +// value, whose default value is zero. If desc.kind = 'full', the output is a +// MATLAB dense matrix. + +// Usage: +// C = gbfull (A) +// C = gbfull (A, type) +// C = gbfull (A, type, id) +// C = gbfull (A, type, id, desc) #include "gb_matlab.h" @@ -25,8 +34,8 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin >= 2 && nargin <= 4 && nargout <= 1, - "usage: C = GrB.full (A, type, id, desc)") ; + gb_usage (nargin >= 1 && nargin <= 4 && nargout <= 2, + "usage: C = gbfull (A, type, id, desc)") ; //-------------------------------------------------------------------------- // get a shallow copy of the input matrix @@ -41,7 +50,16 @@ void mexFunction // get the type of C //-------------------------------------------------------------------------- - GrB_Matrix type = gb_mxstring_to_type (pargin [1]) ; + GrB_Matrix type ; + if (nargin > 1) + { + type = gb_mxstring_to_type (pargin [1]) ; + } + else + { + // the output type defaults to the same as the input type + OK (GxB_Matrix_type (&type, A)) ; + } //-------------------------------------------------------------------------- // get the identity scalar @@ -60,17 +78,18 @@ void mexFunction } //-------------------------------------------------------------------------- - // get the descriptor (kind defaults to KIND_FULL) + // get the descriptor //-------------------------------------------------------------------------- base_enum_t base = BASE_DEFAULT ; - kind_enum_t kind = KIND_FULL ; + kind_enum_t kind = KIND_GRB ; GxB_Format_Value fmt = GxB_NO_FORMAT ; GrB_Descriptor desc = NULL ; if (nargin > 3) { desc = gb_mxarray_to_descriptor (pargin [nargin-1], &kind, &fmt, &base); } + OK (GrB_Descriptor_free (&desc)) ; // A determines the format of C, unless defined by the descriptor fmt = gb_get_format (nrows, ncols, A, NULL, fmt) ; @@ -86,14 +105,35 @@ void mexFunction false) ; //-------------------------------------------------------------------------- - // C = first (A, B) + // typecast A from float to integer using the MATLAB rules + //-------------------------------------------------------------------------- + + GrB_Matrix S, T = NULL ; + GrB_Type atype ; + OK (GxB_Matrix_type (&atype, A)) ; + if (gb_is_integer (type) && gb_is_float (atype)) + { + // T = (type) round (A) + OK (GrB_Matrix_new (&T, type, nrows, ncols)) ; + OK (GxB_Matrix_Option_set (T, GxB_FORMAT, fmt)) ; + OK (GrB_Matrix_apply (T, NULL, NULL, gb_round_binop (atype), A, NULL)) ; + S = T ; + } + else + { + // T = A, and let GrB_Matrix_eWiseAdd_BinaryOp do the typecasting + S = A ; + } + + //-------------------------------------------------------------------------- + // C = first (S, B) //-------------------------------------------------------------------------- GrB_Matrix C ; OK (GrB_Matrix_new (&C, type, nrows, ncols)) ; OK (GxB_Matrix_Option_set (C, GxB_FORMAT, fmt)) ; - OK (GrB_eWiseAdd_Matrix_BinaryOp (C, NULL, NULL, - gb_first_binop (type), A, B, NULL)) ; + OK (GrB_Matrix_eWiseAdd_BinaryOp (C, NULL, NULL, + gb_first_binop (type), S, B, NULL)) ; //-------------------------------------------------------------------------- // free workspace @@ -102,13 +142,14 @@ void mexFunction OK (GrB_Matrix_free (&id)) ; OK (GrB_Matrix_free (&B)) ; OK (GrB_Matrix_free (&A)) ; - OK (GrB_Descriptor_free (&desc)) ; + OK (GrB_Matrix_free (&T)) ; //-------------------------------------------------------------------------- // export C to a MATLAB dense matrix //-------------------------------------------------------------------------- pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbkronecker.c b/GraphBLAS/@GrB/private/mexfunctions/gbkronecker.c index c1a30dab33..5cf04eba97 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbkronecker.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbkronecker.c @@ -7,21 +7,22 @@ //------------------------------------------------------------------------------ -// gbkronecker is an interface to GxB_kron +// gbkronecker is an interface to GrB_kronecker // Usage: -// Cout = GrB.kronecker (op, A, B, desc) -// Cout = GrB.kronecker (Cin, accum, op, A, B, desc) -// Cout = GrB.kronecker (Cin, M, op, A, B, desc) -// Cout = GrB.kronecker (Cin, M, accum, op, A, B, desc) +// C = gbkronecker (op, A, B) +// C = gbkronecker (op, A, B, desc) +// C = gbkronecker (Cin, accum, op, A, B, desc) +// C = gbkronecker (Cin, M, op, A, B, desc) +// C = gbkronecker (Cin, M, accum, op, A, B, desc) // If Cin is not present then it is implicitly a matrix with no entries, of the // right size (which depends on A, B, and the descriptor). #include "gb_matlab.h" -#define USAGE "usage: Cout = GrB.kronecker (Cin, M, accum, op, A, B, desc)" +#define USAGE "usage: C = GrB.kronecker (Cin, M, accum, op, A, B, desc)" void mexFunction ( @@ -36,8 +37,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage ((nargin == 4 || nargin == 6 || nargin == 7) && nargout <= 1, - USAGE) ; + gb_usage (nargin >= 3 && nargin <= 7 && nargout <= 2, USAGE) ; //-------------------------------------------------------------------------- // find the arguments @@ -58,7 +58,7 @@ void mexFunction // get the matrices //-------------------------------------------------------------------------- - GrB_Type atype, ctype = NULL ; + GrB_Type atype, btype, ctype = NULL ; GrB_Matrix C = NULL, M = NULL, A, B ; if (nmatrices == 2) @@ -81,6 +81,7 @@ void mexFunction } OK (GxB_Matrix_type (&atype, A)) ; + OK (GxB_Matrix_type (&btype, B)) ; if (C != NULL) { OK (GxB_Matrix_type (&ctype, C)) ; @@ -94,14 +95,14 @@ void mexFunction if (nstrings == 1) { - op = gb_mxstring_to_binop (String [0], atype) ; + op = gb_mxstring_to_binop (String [0], atype, btype) ; } else { // if accum appears, then Cin must also appear CHECK_ERROR (C == NULL, USAGE) ; - accum = gb_mxstring_to_binop (String [0], ctype) ; - op = gb_mxstring_to_binop (String [1], atype) ; + accum = gb_mxstring_to_binop (String [0], ctype, ctype) ; + op = gb_mxstring_to_binop (String [1], atype, btype) ; } //-------------------------------------------------------------------------- @@ -159,7 +160,7 @@ void mexFunction // compute C += kron (A,B) //-------------------------------------------------------------------------- - OK (GxB_kron (C, M, accum, op, A, B, desc)) ; + OK (GrB_Matrix_kronecker_BinaryOp (C, M, accum, op, A, B, desc)) ; //-------------------------------------------------------------------------- // free shallow copies @@ -175,6 +176,7 @@ void mexFunction //-------------------------------------------------------------------------- pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gblogassign.c b/GraphBLAS/@GrB/private/mexfunctions/gblogassign.c index 9ead80cd1a..1534e7b773 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gblogassign.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gblogassign.c @@ -64,6 +64,10 @@ // GrB_Matrix objects. The m-file above is useful for understanding that this // C mexFunction does. +// C is always returned as a GrB matrix. + +#define ERR "A must be a vector of length nnz(M) for logical indexing, C(M)=A" + #include "gb_matlab.h" void mexFunction @@ -110,24 +114,68 @@ void mexFunction // get A //-------------------------------------------------------------------------- - // make sure A is stored by column, and is nnz(M)-by-1 GrB_Matrix A_input = gb_get_shallow (pargin [2]) ; - GrB_Matrix A, A_copy ; - A = gb_by_col (&A_copy, A_input) ; - - GrB_Index anrows, ancols ; - OK (GrB_Matrix_nrows (&anrows, A)) ; - OK (GrB_Matrix_ncols (&ancols, A)) ; - if (mnz > 0) + GrB_Type atype ; + GrB_Index anrows, ancols, anz ; + GxB_Format_Value fmt ; + OK (GrB_Matrix_nrows (&anrows, A_input)) ; + OK (GrB_Matrix_ncols (&ancols, A_input)) ; + OK (GxB_Matrix_type (&atype, A_input)) ; + OK (GrB_Matrix_nvals (&anz, A_input)) ; + OK (GxB_Matrix_Option_get (A_input, GxB_FORMAT, &fmt)) ; + + // make sure A is a vector of the right size + GrB_Matrix A, A_copy = NULL ; + + if (mnz == 0) { - CHECK_ERROR (anrows != mnz || ancols != 1, "A must be nnz(M)-by-1") ; + // M is empty, so A must have no entries. The dimensions and format of + // A are not relevant, since the content of A will not be accessed. + CHECK_ERROR (anz != 0, ERR) ; + A = A_input ; + } + else if (anrows == 1) + { + // A is 1-by-ancols; ensure it is has length nnz(M), and held by row, + // or transpose to ancols-by-1 and held by column. + CHECK_ERROR (ancols != mnz, ERR) ; + if (fmt == GxB_BY_COL) + { + // A is 1-by-ancols and held by column: transpose it + OK (GrB_Matrix_new (&A_copy, atype, mnz, 1)) ; + OK (GxB_Matrix_Option_set (A_copy, GxB_FORMAT, GxB_BY_COL)) ; + OK (GrB_transpose (A_copy, NULL, NULL, A_input, NULL)) ; + OK (GrB_Matrix_wait (&A_copy)) ; + A = A_copy ; + } + else + { + A = A_input ; + } + } + else if (ancols == 1) + { + // A is anrows-by-1; ensure it is has length nnz(M), and held by col + // or transpose to 1-by-anrows and held by row. + CHECK_ERROR (anrows != mnz, ERR) ; + if (fmt == GxB_BY_ROW) + { + // A is anrows-by-1 and held by row: transpose it + OK (GrB_Matrix_new (&A_copy, atype, 1, mnz)) ; + OK (GxB_Matrix_Option_set (A_copy, GxB_FORMAT, GxB_BY_ROW)) ; + OK (GrB_transpose (A_copy, NULL, NULL, A_input, NULL)) ; + OK (GrB_Matrix_wait (&A_copy)) ; + A = A_copy ; + } + else + { + A = A_input ; + } + } + else + { + ERROR (ERR) ; } - - GrB_Index anz ; - OK (GrB_Matrix_nvals (&anz, A)) ; - - GrB_Type atype ; - OK (GxB_Matrix_type (&atype, A)) ; int64_t *Ai = A->i ; void *Ax = A->x ; @@ -149,7 +197,7 @@ void mexFunction GrB_Index *Si = mxMalloc (MAX (anz, 1) * sizeof (GrB_Index)) ; GrB_Index *Sj = mxMalloc (MAX (anz, 1) * sizeof (GrB_Index)) ; - GB_matlab_helper5 (Si, Sj, Mi, Mj, Ai, anz) ; + GB_matlab_helper5 (Si, Sj, Mi, Mj, (GrB_Index *) Ai, anz) ; GrB_Matrix S ; OK (GrB_Matrix_new (&S, atype, nrows, ncols)) ; @@ -199,17 +247,21 @@ void mexFunction { OK (GrB_Matrix_build_FP64 (S, Si, Sj, Ax, anz, GrB_PLUS_FP64)) ; } - #ifdef GB_COMPLEX_TYPE - else if (atype == gb_complex_type) - { - OK (GrB_Matrix_build_UDT (S, Si, Sj, Ax, anz, ...)) ; + else if (atype == GxB_FC32) + { + OK (GxB_Matrix_build_FC32 (S, Si, Sj, Ax, anz, GxB_PLUS_FC32)) ; + } + else if (atype == GxB_FC64) + { + OK (GxB_Matrix_build_FC64 (S, Si, Sj, Ax, anz, GxB_PLUS_FC64)) ; } - #endif else { ERROR ("unsupported type") ; } + OK (GrB_Matrix_free (&A_copy)) ; + //-------------------------------------------------------------------------- // C = S //-------------------------------------------------------------------------- diff --git a/GraphBLAS/@GrB/private/mexfunctions/gblogextract.c b/GraphBLAS/@GrB/private/mexfunctions/gblogextract.c index a250266307..bc7101cc06 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gblogextract.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gblogextract.c @@ -14,7 +14,7 @@ // Usage: -// C = gblogextract (A, M) +// C = gblogextract (A, M) // This function is the C equivalent of the following m-function: @@ -75,6 +75,8 @@ // structure of the GrB_Matrix objects, and creates shallow copies. The // m-file above is useful for understanding that this C mexFunction does. +// C is always returned as a GrB matrix. + #include "gb_matlab.h" #include "GB_transpose.h" @@ -211,9 +213,9 @@ void mexFunction OK (GrB_Vector_new (&V, type, mnz)) ; gb_mxfree (&V->i) ; gb_mxfree (&V->x) ; - V->i = Tx ; // transplant the values of T as the row indices of V + V->i = (int64_t *) Tx ; // transplant values of T as the row indices of V T->x = NULL ; - V->x = Gx ; // transplant the values of G as the values of V + V->x = Gx ; // transplant the values of G as the values of V V->nzmax = tnvals ; int64_t *Vp = V->p ; Vp [0] = 0 ; diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbmonoidinfo.c b/GraphBLAS/@GrB/private/mexfunctions/gbmonoidinfo.c index f7a264aef2..c969ac2656 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbmonoidinfo.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbmonoidinfo.c @@ -27,7 +27,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin <= 2 && nargout == 0, + gb_usage (nargin >= 1 && nargin <= 2 && nargout == 0, "usage: GrB.monoidinfo (monoid) or GrB.monoidinfo (monoid,type)") ; //-------------------------------------------------------------------------- @@ -39,7 +39,7 @@ void mexFunction gb_mxstring_to_string (opstring, LEN, pargin [0], "binary operator") ; GrB_Type type = NULL ; - if (nargin == 2) + if (nargin > 1) { type = gb_mxstring_to_type (pargin [1]) ; CHECK_ERROR (type == NULL, "unknown type") ; diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbmxm.c b/GraphBLAS/@GrB/private/mexfunctions/gbmxm.c index 56c5667609..a2719a3077 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbmxm.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbmxm.c @@ -11,17 +11,18 @@ // Usage: -// Cout = GrB.mxm (semiring, A, B, desc) -// Cout = GrB.mxm (Cin, accum, semiring, A, B, desc) -// Cout = GrB.mxm (Cin, M, semiring, A, B, desc) -// Cout = GrB.mxm (Cin, M, accum, semiring, A, B, desc) +// C = gbmxm (semiring, A, B) +// C = gbmxm (semiring, A, B, desc) +// C = gbmxm (Cin, accum, semiring, A, B, desc) +// C = gbmxm (Cin, M, semiring, A, B, desc) +// C = gbmxm (Cin, M, accum, semiring, A, B, desc) // If Cin is not present then it is implicitly a matrix with no entries, of the // right size (which depends on A, B, and the descriptor). #include "gb_matlab.h" -#define USAGE "usage: Cout = GrB.mxm (Cin, M, accum, semiring, A, B, desc)" +#define USAGE "usage: C = GrB.mxm (Cin, M, accum, semiring, A, B, desc)" void mexFunction ( @@ -36,8 +37,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage ((nargin == 4 || nargin == 6 || nargin == 7) && nargout <= 1, - USAGE) ; + gb_usage (nargin >= 3 && nargin <= 7 && nargout <= 2, USAGE) ; //-------------------------------------------------------------------------- // find the arguments @@ -58,7 +58,7 @@ void mexFunction // get the matrices //-------------------------------------------------------------------------- - GrB_Type atype, ctype = NULL ; + GrB_Type atype, btype, ctype = NULL ; GrB_Matrix C = NULL, M = NULL, A, B ; if (nmatrices == 2) @@ -81,6 +81,7 @@ void mexFunction } OK (GxB_Matrix_type (&atype, A)) ; + OK (GxB_Matrix_type (&btype, B)) ; if (C != NULL) { OK (GxB_Matrix_type (&ctype, C)) ; @@ -95,14 +96,14 @@ void mexFunction if (nstrings == 1) { - semiring = gb_mxstring_to_semiring (String [0], atype) ; + semiring = gb_mxstring_to_semiring (String [0], atype, btype) ; } else { // if accum appears, then Cin must also appear CHECK_ERROR (C == NULL, USAGE) ; - accum = gb_mxstring_to_binop (String [0], ctype) ; - semiring = gb_mxstring_to_semiring (String [1], atype) ; + accum = gb_mxstring_to_binop (String [0], ctype, ctype) ; + semiring = gb_mxstring_to_semiring (String [1], atype, btype) ; } //-------------------------------------------------------------------------- @@ -164,6 +165,7 @@ void mexFunction //-------------------------------------------------------------------------- pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbnew.c b/GraphBLAS/@GrB/private/mexfunctions/gbnew.c index 5d31c71539..34e9bc32f8 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbnew.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbnew.c @@ -10,6 +10,19 @@ // A may be a MATLAB sparse matrix, or a MATLAB struct containing a GraphBLAS // matrix. C is returned as a MATLAB struct containing a GraphBLAS matrix. +// Usage: + +// C = gbnew (A) +// C = gbnew (A, type) +// C = gbnew (A, format) +// C = gbnew (m, n) +// C = gbnew (m, n, format) +// C = gbnew (m, n, type) +// C = gbnew (A, type, format) +// C = gbnew (A, format, type) +// C = gbnew (m, n, type, format) +// C = gbnew (m, n, format, type) + #include "gb_matlab.h" void mexFunction diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbnorm.c b/GraphBLAS/@GrB/private/mexfunctions/gbnorm.c index d1c8a1faec..e3234ee619 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbnorm.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbnorm.c @@ -47,13 +47,13 @@ void mexFunction double s ; if (norm_kind == INT64_MIN && !GB_is_dense (A)) - { + { // norm (A,-inf) is zero if A is not dense s = 0 ; } else if ((atype == GrB_FP32 || atype == GrB_FP64) && (anrows == 1 || ancols == 1 || norm_kind == 0)) - { + { // s = norm (A,p) where A is an FP32 or FP64 vector, // or when p = 0 (for Frobenius norm) GrB_Index anz ; @@ -62,7 +62,7 @@ void mexFunction if (s < 0) ERROR ("unknown norm") ; } else - { + { // s = norm (A, norm_kind) s = gb_norm (A, norm_kind) ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbnormdiff.c b/GraphBLAS/@GrB/private/mexfunctions/gbnormdiff.c index 73ee9c515f..833a00f15e 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbnormdiff.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbnormdiff.c @@ -70,12 +70,27 @@ void mexFunction GrB_Type xtype ; GrB_BinaryOp op ; if (atype == GrB_FP32 && atype == btype) - { + { + // both A and B are single: use FP32 xtype = GrB_FP32 ; op = GrB_MINUS_FP32 ; } + else if (atype == GxB_FC32 && btype == GxB_FC32) + { + // both A and B are single complex: use FC32 + xtype = GxB_FC32 ; + op = GxB_MINUS_FC32 ; + } + else if (atype == GxB_FC64 || btype == GxB_FC64 || + atype == GxB_FC32 || btype == GxB_FC32) + { + // either A or B are any kind of complex: use FC64 + xtype = GxB_FC64 ; + op = GxB_MINUS_FC64 ; + } else - { + { + // both A and B are real (any kind): use FP64 xtype = GrB_FP64 ; op = GrB_MINUS_FP64 ; } @@ -83,7 +98,7 @@ void mexFunction // X = A-B GrB_Matrix X ; OK (GrB_Matrix_new (&X, xtype, anrows, ancols)) ; - OK (GrB_eWiseAdd_Matrix_BinaryOp (X, NULL, NULL, op, A, B, NULL)) ; + OK (GrB_Matrix_eWiseAdd_BinaryOp (X, NULL, NULL, op, A, B, NULL)) ; // s = norm (X, norm_kind) s = gb_norm (X, norm_kind) ; diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbnvals.c b/GraphBLAS/@GrB/private/mexfunctions/gbnvals.c index f3ef03a05d..6f9dcbc600 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbnvals.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbnvals.c @@ -10,6 +10,10 @@ // The input may be either a GraphBLAS matrix struct or a standard MATLAB // sparse matrix. +// Usage + +// nvals = gbnvals (X) + #include "gb_matlab.h" void mexFunction @@ -25,7 +29,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin == 1 && nargout <= 1, "usage: nvals = GrB.nvals (X)") ; + gb_usage (nargin == 1 && nargout <= 1, "usage: nvals = gbnvals (X)") ; //-------------------------------------------------------------------------- // get the # of entries in the matrix diff --git a/GraphBLAS/@GrB/private/mexfunctions/gboptype.c b/GraphBLAS/@GrB/private/mexfunctions/gboptype.c new file mode 100644 index 0000000000..f93beb74fc --- /dev/null +++ b/GraphBLAS/@GrB/private/mexfunctions/gboptype.c @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// gboptype : determine the type of a binary operator from the input types +//------------------------------------------------------------------------------ + +// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. +// http://suitesparse.com See GraphBLAS/Doc/License.txt for license. + +//------------------------------------------------------------------------------ + +// Usage: + +// optype = gboptype (atype, btype) + +#include "gb_matlab.h" + +void mexFunction +( + int nargout, + mxArray *pargout [ ], + int nargin, + const mxArray *pargin [ ] +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + gb_usage (nargin == 2 && nargout <= 1, "usage: c = GrB.optype (a, b)"); + + //-------------------------------------------------------------------------- + // get atype and btype + //-------------------------------------------------------------------------- + + GrB_Type atype = gb_mxstring_to_type (pargin [0]) ; + GrB_Type btype = gb_mxstring_to_type (pargin [1]) ; + + //-------------------------------------------------------------------------- + // determine the optype + //-------------------------------------------------------------------------- + + GrB_Type optype = gb_default_type (atype, btype) ; + CHECK_ERROR (optype == NULL, "unknown type") ; + + //-------------------------------------------------------------------------- + // return result as a string + //-------------------------------------------------------------------------- + + pargout [0] = gb_type_to_mxstring (optype) ; + GB_WRAPUP ; +} + diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbreduce.c b/GraphBLAS/@GrB/private/mexfunctions/gbreduce.c index 55159019f2..acaaa9b397 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbreduce.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbreduce.c @@ -11,14 +11,15 @@ // Usage: -// cout = GrB.reduce (op, A, desc) -// cout = GrB.reduce (cin, accum, op, A, desc) +// cout = gbreduce (op, A) +// cout = gbreduce (op, A, desc) +// cout = gbreduce (cin, accum, op, A, desc) // If cin is not present then it is implicitly a 1-by-1 matrix with no entries. #include "gb_matlab.h" -#define USAGE "usage: Cout = GrB.reduce (cin, accum, op, A, desc)" +#define USAGE "usage: C = GrB.reduce (cin, accum, op, A, desc)" void mexFunction ( @@ -33,7 +34,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage ((nargin == 3 || nargin == 5) && nargout <= 1, USAGE) ; + gb_usage (nargin >= 2 && nargin <= 5 && nargout <= 2, USAGE) ; //-------------------------------------------------------------------------- // find the arguments @@ -89,7 +90,7 @@ void mexFunction { // if accum appears, then Cin must also appear CHECK_ERROR (C == NULL, USAGE) ; - accum = gb_mxstring_to_binop (String [0], ctype) ; + accum = gb_mxstring_to_binop (String [0], ctype, ctype) ; monoid = gb_mxstring_to_monoid (String [1], atype) ; } @@ -214,15 +215,20 @@ void mexFunction OK (GrB_Matrix_reduce_FP64 (&c, accum, monoid, A, desc)) ; OK (GrB_Matrix_setElement_FP64 (C, c, 0, 0)) ; } - #ifdef GB_COMPLEX_TYPE - else if (ctype == gb_complex_type) - { - double complex c = 0 ; - OK (GrB_Matrix_extractElement_UDT (&c, C, 0, 0)) ; - OK (GrB_Matrix_reduce_UDT (&c, accum, monoid, A, desc)) ; - OK (GrB_Matrix_setElement_UDT (C, c, 0, 0)) ; + else if (ctype == GxB_FC32) + { + GxB_FC32_t c = GxB_CMPLXF (0,0) ; + OK (GxB_Matrix_extractElement_FC32 (&c, C, 0, 0)) ; + OK (GxB_Matrix_reduce_FC32 (&c, accum, monoid, A, desc)) ; + OK (GxB_Matrix_setElement_FC32 (C, c, 0, 0)) ; + } + else if (ctype == GxB_FC64) + { + GxB_FC64_t c = GxB_CMPLX (0,0) ; + OK (GxB_Matrix_extractElement_FC64 (&c, C, 0, 0)) ; + OK (GxB_Matrix_reduce_FC64 (&c, accum, monoid, A, desc)) ; + OK (GxB_Matrix_setElement_FC64 (C, c, 0, 0)) ; } - #endif else { ERROR ("unsupported type") ; @@ -240,6 +246,7 @@ void mexFunction //-------------------------------------------------------------------------- pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbselect.c b/GraphBLAS/@GrB/private/mexfunctions/gbselect.c index ce43f42dc7..deb5c07e85 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbselect.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbselect.c @@ -11,33 +11,38 @@ // Usage: -// Cout = gbselect (op, A, desc) -// Cout = gbselect (op, A, b, desc) +// C = gbselect (op, A) +// C = gbselect (op, A, desc) +// C = gbselect (op, A, b, desc) -// Cout = gbselect (Cin, accum, op, A, desc) -// Cout = gbselect (Cin, accum, op, A, b, desc) +// C = gbselect (Cin, accum, op, A, desc) +// C = gbselect (Cin, accum, op, A, b, desc) -// Cout = gbselect (Cin, M, op, A, desc) -// Cout = gbselect (Cin, M, op, A, b, desc) +// C = gbselect (Cin, M, op, A, desc) +// C = gbselect (Cin, M, op, A, b, desc) -// Cout = gbselect (Cin, M, accum, op, A, desc) -// Cout = gbselect (Cin, M, accum, op, A, b, desc) +// C = gbselect (Cin, M, accum, op, A, desc) +// C = gbselect (Cin, M, accum, op, A, b, desc) // If Cin is not present then it is implicitly a matrix with no entries, of the // right size (which depends on A, and the descriptor). The type if Cin, if // not present, is determined by the ztype of the accum, if present, or // otherwise it has the same time as A. -// If op is '==' or '~=' and b is a NaN, and A has type GrB_FP32 or GrB_FP64, -// then a user-defined operator is used instead of GxB_EQ_THUNK or -// GxB_NE_THUNK. +// If op is '==' or '~=' and b is a NaN, and A has type GrB_FP32, GrB_FP64, +// GxB_FC32, or GxB_FC64, then a user-defined operator is used instead of +// GxB_EQ_THUNK or GxB_NE_THUNK. // The 'tril', 'triu', 'diag', 'offdiag', and 2-input operators all require // the b scalar. The b scalar must not appear for the '*0' operators. #include "gb_matlab.h" -#define USAGE "usage: Cout = GrB.select (Cin, M, accum, op, A, b, desc)" +#define USAGE "usage: C = GrB.select (Cin, M, accum, op, A, b, desc)" + +//------------------------------------------------------------------------------ +// nan operators +//------------------------------------------------------------------------------ bool gb_isnan32 (GrB_Index i, GrB_Index j, GrB_Index nrows, GrB_Index ncols, const void *x, const void *b) @@ -67,6 +72,38 @@ bool gb_isnotnan64 (GrB_Index i, GrB_Index j, GrB_Index nrows, GrB_Index ncols, return (!isnan (aij)) ; } +bool gb_isnanfc32 (GrB_Index i, GrB_Index j, GrB_Index nrows, + GrB_Index ncols, const void *x, const void *b) +{ + GxB_FC32_t aij = * ((GxB_FC32_t *) x) ; + return (isnan (crealf (aij)) || isnan (cimagf (aij))) ; +} + +bool gb_isnanfc64 (GrB_Index i, GrB_Index j, GrB_Index nrows, + GrB_Index ncols, const void *x, const void *b) +{ + GxB_FC64_t aij = * ((GxB_FC64_t *) x) ; + return (isnan (creal (aij)) || isnan (cimag (aij))) ; +} + +bool gb_isnotnanfc32 (GrB_Index i, GrB_Index j, GrB_Index nrows, + GrB_Index ncols, const void *x, const void *b) +{ + GxB_FC32_t aij = * ((GxB_FC32_t *) x) ; + return (!isnan (crealf (aij)) && !isnan (cimagf (aij))) ; +} + +bool gb_isnotnanfc64 (GrB_Index i, GrB_Index j, GrB_Index nrows, + GrB_Index ncols, const void *x, const void *b) +{ + GxB_FC64_t aij = * ((GxB_FC64_t *) x) ; + return (!isnan (creal (aij)) && !isnan (cimag (aij))) ; +} + +//------------------------------------------------------------------------------ +// gbselect mexFunction +//------------------------------------------------------------------------------ + void mexFunction ( int nargout, @@ -80,7 +117,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin >= 3 && nargin <= 7 && nargout <= 1, USAGE) ; + gb_usage (nargin >= 2 && nargin <= 7 && nargout <= 2, USAGE) ; //-------------------------------------------------------------------------- // find the arguments @@ -180,7 +217,7 @@ void mexFunction { // if accum appears, then Cin must also appear CHECK_ERROR (C == NULL, USAGE) ; - accum = gb_mxstring_to_binop (String [0], ctype) ; + accum = gb_mxstring_to_binop (String [0], ctype, ctype) ; } //-------------------------------------------------------------------------- @@ -239,6 +276,18 @@ void mexFunction OK (GrB_Matrix_extractElement_FP64 (&b_value, b, 0, 0)) ; b_is_nan = isnan (b_value) ; } + else if (b_type == GxB_FC32) + { + GxB_FC32_t b_value = GxB_CMPLXF (0, 0) ; + OK (GxB_Matrix_extractElement_FC32 (&b_value, b, 0, 0)) ; + b_is_nan = GB_cisnanf (b_value) ; + } + else if (b_type == GxB_FC64) + { + GxB_FC64_t b_value = GxB_CMPLX (0, 0) ; + OK (GxB_Matrix_extractElement_FC64 (&b_value, b, 0, 0)) ; + b_is_nan = GB_cisnan (b_value) ; + } if (b_is_nan) { @@ -246,23 +295,52 @@ void mexFunction // instead of the built-in GxB_EQ_THUNK or GxB_NE_THUNK operators. // These operators do not need a b input, since it is now known // to be a NaN. - if (op == GxB_EQ_THUNK && atype == GrB_FP32) - { - OK (GxB_SelectOp_new (&nan_test, gb_isnan32, GrB_FP32, NULL)) ; - } - else if (op == GxB_EQ_THUNK && atype == GrB_FP64) - { - OK (GxB_SelectOp_new (&nan_test, gb_isnan64, GrB_FP64, NULL)) ; - } - else if (op == GxB_NE_THUNK && atype == GrB_FP32) - { - OK (GxB_SelectOp_new (&nan_test, gb_isnotnan32, GrB_FP32, - NULL)) ; + + if (op == GxB_EQ_THUNK) + { + if (atype == GrB_FP32) + { + OK (GxB_SelectOp_new (&nan_test, gb_isnan32, + GrB_FP32, NULL)) ; + } + else if (atype == GrB_FP64) + { + OK (GxB_SelectOp_new (&nan_test, gb_isnan64, + GrB_FP64, NULL)) ; + } + else if (atype == GxB_FC32) + { + OK (GxB_SelectOp_new (&nan_test, gb_isnanfc32, + GxB_FC32, NULL)) ; + } + else if (atype == GxB_FC64) + { + OK (GxB_SelectOp_new (&nan_test, gb_isnanfc64, + GxB_FC64, NULL)) ; + } } - else if (op == GxB_NE_THUNK && atype == GrB_FP64) - { - OK (GxB_SelectOp_new (&nan_test, gb_isnotnan64, GrB_FP64, - NULL)) ; + else if (op == GxB_NE_THUNK) + { + if (atype == GrB_FP32) + { + OK (GxB_SelectOp_new (&nan_test, gb_isnotnan32, + GrB_FP32, NULL)) ; + } + else if (atype == GrB_FP64) + { + OK (GxB_SelectOp_new (&nan_test, gb_isnotnan64, + GrB_FP64, NULL)) ; + } + else if (atype == GxB_FC32) + { + OK (GxB_SelectOp_new (&nan_test, gb_isnotnanfc32, + GxB_FC32, NULL)) ; + } + else if (atype == GxB_FC64) + { + OK (GxB_SelectOp_new (&nan_test, gb_isnotnanfc64, + GxB_FC64, NULL)) ; + } } } @@ -295,6 +373,7 @@ void mexFunction //-------------------------------------------------------------------------- pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbselectopinfo.c b/GraphBLAS/@GrB/private/mexfunctions/gbselectopinfo.c index 01440f2c2f..b3f50adf7c 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbselectopinfo.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbselectopinfo.c @@ -26,7 +26,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin <= 1 && nargout == 0, + gb_usage (nargin == 1 && nargout == 0, "usage: GrB.selectopinfo (selectop)") ; //-------------------------------------------------------------------------- diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbsemiringinfo.c b/GraphBLAS/@GrB/private/mexfunctions/gbsemiringinfo.c index 46acfba61a..c5f4c18353 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbsemiringinfo.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbsemiringinfo.c @@ -27,7 +27,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin <= 2 && nargout == 0, + gb_usage (nargin >= 1 && nargin <= 2 && nargout == 0, "usage: GrB.semiringinfo (semiring) or GrB.semiringinfo (semiring,type)") ; //-------------------------------------------------------------------------- @@ -39,13 +39,13 @@ void mexFunction gb_mxstring_to_string (opstring, LEN, pargin [0], "binary operator") ; GrB_Type type = NULL ; - if (nargin == 2) + if (nargin > 1) { type = gb_mxstring_to_type (pargin [1]) ; CHECK_ERROR (type == NULL, "unknown type") ; } - GrB_Semiring semiring = gb_mxstring_to_semiring (pargin [0], type) ; + GrB_Semiring semiring = gb_mxstring_to_semiring (pargin [0], type, type) ; OK (GxB_Semiring_fprint (semiring, opstring, GxB_COMPLETE, NULL)) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbsize.c b/GraphBLAS/@GrB/private/mexfunctions/gbsize.c index 92e3503768..f424eee218 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbsize.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbsize.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// gbsize: number of rows and columns in a GraphBLAS matrix struct +// gbsize: dimension and type of a GraphBLAS or MATLAB matrix //------------------------------------------------------------------------------ // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. @@ -8,8 +8,12 @@ //------------------------------------------------------------------------------ // The input may be either a GraphBLAS matrix struct or a standard MATLAB -// sparse matrix. Note that the output is int64, to accomodate huge -// hypersparse matrices. +// matrix. Note that the output may be int64, to accomodate huge hypersparse +// matrices. Also returns the type of the matrix. + +// Usage: + +// [m, n, type] = gbsize (X) #include "gb_matlab.h" @@ -26,65 +30,90 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin == 1 && nargout <= 2, "usage: [m n] = GrB.size (X)") ; + gb_usage (nargin == 1 && nargout <= 4, "usage: [m n type] = gbsize (X)") ; //-------------------------------------------------------------------------- - // get the # of rows and columns in a GraphBLAS matrix struct + // get the # of rows and columns of a GraphBLAS or MATLAB matrix //-------------------------------------------------------------------------- - GrB_Matrix X = gb_get_shallow (pargin [0]) ; - GrB_Index nrows, ncols ; - OK (GrB_Matrix_nrows (&nrows, X)) ; - OK (GrB_Matrix_ncols (&ncols, X)) ; + int typecode = -1 ; - //-------------------------------------------------------------------------- - // return result as int64 or double - //-------------------------------------------------------------------------- + if (mxIsStruct (pargin [0])) + { - if (nrows > FLINTMAX || ncols > FLINTMAX) - { - // output is int64 to avoid flint overflow - int64_t *p ; - if (nargout <= 1) - { - pargout [0] = mxCreateNumericMatrix (1, 2, mxINT64_CLASS, mxREAL) ; - p = mxGetInt64s (pargout [0]) ; - p [0] = (int64_t) nrows ; - p [1] = (int64_t) ncols ; - } - else + //---------------------------------------------------------------------- + // get the size of a GraphBLAS matrix + //---------------------------------------------------------------------- + + // get the scalar info + mxArray *opaque = mxGetField (pargin [0], 0, "s") ; + CHECK_ERROR (opaque == NULL, "invalid GraphBLAS struct") ; + int64_t *s = mxGetInt64s (opaque) ; + int64_t vlen = s [1] ; + int64_t vdim = s [2] ; + bool is_csc = (bool) (s [6]) ; + + nrows = (is_csc) ? vlen : vdim ; + ncols = (is_csc) ? vdim : vlen ; + + //---------------------------------------------------------------------- + // get the type of a GraphBLAS matrix, if requested + //---------------------------------------------------------------------- + + if (nargout > 2) { - pargout [0] = mxCreateNumericMatrix (1, 1, mxINT64_CLASS, mxREAL) ; - p = mxGetInt64s (pargout [0]) ; - p [0] = (int64_t) nrows ; - pargout [1] = mxCreateNumericMatrix (1, 1, mxINT64_CLASS, mxREAL) ; - p = mxGetInt64s (pargout [1]) ; - p [0] = (int64_t) ncols ; + // get the type + mxArray *mx_type = mxGetField (pargin [0], 0, "GraphBLAS") ; + CHECK_ERROR (mx_type == NULL, "invalid GraphBLAS struct") ; + pargout [2] = mxDuplicateArray (mx_type) ; } + } else { - // output is double - if (nargout <= 1) - { - pargout [0] = mxCreateDoubleMatrix (1, 2, mxREAL) ; - double *p = mxGetDoubles (pargout [0]) ; - p [0] = (double) nrows ; - p [1] = (double) ncols ; - } - else + + //---------------------------------------------------------------------- + // get the size of a MATLAB matrix + //---------------------------------------------------------------------- + + nrows = (GrB_Index) mxGetM (pargin [0]) ; + ncols = (GrB_Index) mxGetN (pargin [0]) ; + + //---------------------------------------------------------------------- + // get the type of a MATLAB matrix, if requested + //---------------------------------------------------------------------- + + if (nargout > 2) { - pargout [0] = mxCreateDoubleScalar ((double) nrows) ; - pargout [1] = mxCreateDoubleScalar ((double) ncols) ; + mxClassID class = mxGetClassID (pargin [0]) ; + bool is_complex = mxIsComplex (pargin [0]) ; + pargout [2] = gb_mxclass_to_mxstring (class, is_complex) ; } } //-------------------------------------------------------------------------- - // free shallow copy of X + // return the size as int64 or double //-------------------------------------------------------------------------- - OK (GrB_Matrix_free (&X)) ; + if (nrows > FLINTMAX || ncols > FLINTMAX) + { + // output is int64 to avoid flint overflow + int64_t *p ; + pargout [0] = mxCreateNumericMatrix (1, 1, mxINT64_CLASS, mxREAL) ; + p = mxGetInt64s (pargout [0]) ; + p [0] = (int64_t) nrows ; + pargout [1] = mxCreateNumericMatrix (1, 1, mxINT64_CLASS, mxREAL) ; + p = mxGetInt64s (pargout [1]) ; + p [0] = (int64_t) ncols ; + } + else + { + // output is double + pargout [0] = mxCreateDoubleScalar ((double) nrows) ; + pargout [1] = mxCreateDoubleScalar ((double) ncols) ; + } + GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbsparse.c b/GraphBLAS/@GrB/private/mexfunctions/gbsparse.c index f7bda51da6..1b1b7ce8e0 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbsparse.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbsparse.c @@ -10,6 +10,10 @@ // The input may be either a GraphBLAS matrix struct or a standard MATLAB // sparse matrix. The output is a standard MATLAB sparse matrix. +// Usage: + +// A = gbsparse (X, type) + #include "gb_matlab.h" void mexFunction @@ -40,9 +44,10 @@ void mexFunction //-------------------------------------------------------------------------- GrB_Type type = gb_mxstring_to_type (pargin [1]) ; + GrB_Matrix T = NULL ; if (type != xtype) { - GrB_Matrix T = gb_typecast (type, GxB_BY_COL, X) ; + T = gb_typecast (type, GxB_BY_COL, X) ; OK (GrB_Matrix_free (&X)) ; X = T ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbsubassign.c b/GraphBLAS/@GrB/private/mexfunctions/gbsubassign.c index d96f9d7db4..3d3b311414 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbsubassign.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbsubassign.c @@ -16,9 +16,9 @@ // Usage: -// Cout = gbsubassign (Cin, M, accum, A, I, J, desc) +// C = gbsubassign (Cin, M, accum, A, I, J, desc) -// Cin, A, and desc are required. See GrB.m for more details. +// Cin and A required. See GrB.m for more details. #include "gb_matlab.h" @@ -31,6 +31,6 @@ void mexFunction ) { gb_assign (nargout, pargout, nargin, pargin, true, - "usage: Cout = GrB.subassign (Cin, M, accum, A, I, J, desc)") ; + "usage: C = GrB.subassign (Cin, M, accum, A, I, J, desc)") ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbthreads.c b/GraphBLAS/@GrB/private/mexfunctions/gbthreads.c index 5d70d77e7d..6ff3b62d04 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbthreads.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbthreads.c @@ -7,6 +7,11 @@ //------------------------------------------------------------------------------ +// Usage: + +// nthreads = gbthreads +// nthreads = gbthreads (nthreads) + #include "gb_matlab.h" void mexFunction diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbtrans.c b/GraphBLAS/@GrB/private/mexfunctions/gbtrans.c index e7036a4c57..20607a7d4f 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbtrans.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbtrans.c @@ -11,10 +11,11 @@ // Usage: -// Cout = GrB.trans (A, desc) -// Cout = GrB.trans (Cin, accum, A, desc) -// Cout = GrB.trans (Cin, M, A, desc) -// Cout = GrB.trans (Cin, M, accum, A, desc) +// C = gbtrans (A) +// C = gbtrans (A, desc) +// C = gbtrans (Cin, accum, A, desc) +// C = gbtrans (Cin, M, A, desc) +// C = gbtrans (Cin, M, accum, A, desc) // If Cin is not present then it is implicitly a matrix with no entries, of the // right size (which depends on A and the descriptor). Note that if desc.in0 @@ -23,7 +24,7 @@ #include "gb_matlab.h" -#define USAGE "usage: Cout = GrB.trans (Cin, M, accum, A, desc)" +#define USAGE "usage: C = GrB.trans (Cin, M, accum, A, desc)" void mexFunction ( @@ -38,8 +39,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage ((nargin == 2 || nargin == 4 || nargin == 5) && nargout <= 1, - USAGE) ; + gb_usage (nargin >= 1 && nargin <= 5 && nargout <= 2, USAGE) ; //-------------------------------------------------------------------------- // find the arguments @@ -96,7 +96,7 @@ void mexFunction { // if accum appears, then Cin must also appear CHECK_ERROR (C == NULL, USAGE) ; - accum = gb_mxstring_to_binop (String [0], ctype) ; + accum = gb_mxstring_to_binop (String [0], ctype, ctype) ; } //-------------------------------------------------------------------------- @@ -149,6 +149,7 @@ void mexFunction //-------------------------------------------------------------------------- pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbtype.c b/GraphBLAS/@GrB/private/mexfunctions/gbtype.c index a21c0c6630..8d5204f97e 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbtype.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbtype.c @@ -10,6 +10,10 @@ // The input may be any MATLAB variable. If it is a GraphBLAS G.opaque struct, // then its internal type is returned. +// Usage + +// type = gbtype (X) + #include "gb_matlab.h" void mexFunction @@ -25,7 +29,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin == 1 && nargout <= 1, "usage: type = GrB.type (X)") ; + gb_usage (nargin == 1 && nargout <= 1, "usage: type = gbtype (X)") ; //-------------------------------------------------------------------------- // get the type of the matrix @@ -33,6 +37,7 @@ void mexFunction mxArray *c = NULL ; mxClassID class = mxGetClassID (pargin [0]) ; + bool is_complex = mxIsComplex (pargin [0]) ; if (class == mxSTRUCT_CLASS) { @@ -40,54 +45,15 @@ void mexFunction if (mx_type != NULL) { // X is a GraphBLAS G.opaque struct; get its type - GrB_Type type = gb_mxstring_to_type (mx_type) ; - if (type == GrB_BOOL ) c = mxCreateString ("logical") ; - else if (type == GrB_INT8 ) c = mxCreateString ("int8") ; - else if (type == GrB_INT16 ) c = mxCreateString ("int16") ; - else if (type == GrB_INT32 ) c = mxCreateString ("int32") ; - else if (type == GrB_INT64 ) c = mxCreateString ("int64") ; - else if (type == GrB_UINT8 ) c = mxCreateString ("uint8") ; - else if (type == GrB_UINT16) c = mxCreateString ("uint16") ; - else if (type == GrB_UINT32) c = mxCreateString ("uint32") ; - else if (type == GrB_UINT64) c = mxCreateString ("uint64") ; - else if (type == GrB_FP32 ) c = mxCreateString ("single") ; - else if (type == GrB_FP64 ) c = mxCreateString ("double") ; - #ifdef GB_COMPLEX_TYPE - else if (type == gb_complex_type) c = mxCreateString ("complex") ; - #endif - else ERROR ("unknown GraphBLAS type") ; + c = mxDuplicateArray (mx_type) ; } } if (c == NULL) - { - // if c is still NULL, then it is not a GraphBLAS opaque struct - switch (class) - { - // a MATLAB sparse or dense matrix, valid for G = GrB (X), or - // for inputs to any GrB.method. - case mxLOGICAL_CLASS : c = mxCreateString ("logical") ; break ; - case mxINT8_CLASS : c = mxCreateString ("int8") ; break ; - case mxINT16_CLASS : c = mxCreateString ("int16") ; break ; - case mxINT32_CLASS : c = mxCreateString ("int32") ; break ; - case mxINT64_CLASS : c = mxCreateString ("int64") ; break ; - case mxUINT8_CLASS : c = mxCreateString ("uint8") ; break ; - case mxUINT16_CLASS : c = mxCreateString ("uint16") ; break ; - case mxUINT32_CLASS : c = mxCreateString ("uint32") ; break ; - case mxUINT64_CLASS : c = mxCreateString ("uint64") ; break ; - case mxSINGLE_CLASS : c = mxCreateString ("single") ; break ; - case mxDOUBLE_CLASS : c = mxCreateString ("double") ; break ; - - // a MATLAB struct, cell, char, void, function, or unknown - case mxSTRUCT_CLASS : c = mxCreateString ("struct") ; break ; - case mxCELL_CLASS : c = mxCreateString ("cell") ; break ; - case mxCHAR_CLASS : c = mxCreateString ("char") ; break ; - case mxVOID_CLASS : c = mxCreateString ("void") ; break ; - case mxFUNCTION_CLASS : c = mxCreateString ("function_handle") ; - break ; - case mxUNKNOWN_CLASS : - default : c = mxCreateString ("unknown") ; break ; - } + { + // if c is still NULL, then it is not a GraphBLAS opaque struct. + // get the type of a MATLAB matrix + c = gb_mxclass_to_mxstring (class, is_complex) ; } //-------------------------------------------------------------------------- diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbunopinfo.c b/GraphBLAS/@GrB/private/mexfunctions/gbunopinfo.c index d25e2fcf26..488af41995 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbunopinfo.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbunopinfo.c @@ -27,7 +27,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin <= 2 && nargout == 0, + gb_usage (nargin >= 1 && nargin <= 2 && nargout == 0, "usage: GrB.unopinfo (unop) or GrB.unopinfo (unop,type)") ; //-------------------------------------------------------------------------- diff --git a/GraphBLAS/@GrB/private/mexfunctions/gbvreduce.c b/GraphBLAS/@GrB/private/mexfunctions/gbvreduce.c index c1552256f3..8d1e54ddfd 100644 --- a/GraphBLAS/@GrB/private/mexfunctions/gbvreduce.c +++ b/GraphBLAS/@GrB/private/mexfunctions/gbvreduce.c @@ -11,17 +11,18 @@ // Usage: -// Cout = GrB.vreduce (op, A, desc) -// Cout = GrB.vreduce (Cin, M, op, A, desc) -// Cout = GrB.vreduce (Cin, accum, op, A, desc) -// Cout = GrB.vreduce (Cin, M, accum, op, A, desc) +// C = gbvreduce (op, A) +// C = gbvreduce (op, A, desc) +// C = gbvreduce (Cin, M, op, A, desc) +// C = gbvreduce (Cin, accum, op, A, desc) +// C = gbvreduce (Cin, M, accum, op, A, desc) // If Cin is not present then it is implicitly a matrix with no entries, of the // right size (which depends on A and the descriptor). #include "gb_matlab.h" -#define USAGE "usage: Cout = GrB.vreduce (Cin, M, accum, op, A, desc)" +#define USAGE "usage: C = GrB.vreduce (Cin, M, accum, op, A, desc)" void mexFunction ( @@ -36,8 +37,7 @@ void mexFunction // check inputs //-------------------------------------------------------------------------- - gb_usage ((nargin == 3 || nargin == 5 || nargin == 6) && nargout <= 1, - USAGE) ; + gb_usage (nargin >= 2 && nargin <= 6 && nargout <= 2, USAGE) ; //-------------------------------------------------------------------------- // find the arguments @@ -102,7 +102,7 @@ void mexFunction { // if accum appears, then Cin must also appear CHECK_ERROR (C == NULL, USAGE) ; - accum = gb_mxstring_to_binop (String [0], ctype) ; + accum = gb_mxstring_to_binop (String [0], ctype, ctype) ; monoid = gb_mxstring_to_monoid (String [1], atype) ; } @@ -157,6 +157,7 @@ void mexFunction //-------------------------------------------------------------------------- pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/util/gb_abort.c b/GraphBLAS/@GrB/private/util/gb_abort.c index b63d4eb2ab..0f23a08393 100644 --- a/GraphBLAS/@GrB/private/util/gb_abort.c +++ b/GraphBLAS/@GrB/private/util/gb_abort.c @@ -9,8 +9,8 @@ #include "gb_matlab.h" -void gb_abort ( void ) // assertion failure +void gb_abort ( void ) // failure { - mexErrMsgIdAndTxt ("GraphBLAS:assert", "assertion failed") ; + mexErrMsgIdAndTxt ("GraphBLAS:abort", "GraphBLAS failed") ; } diff --git a/GraphBLAS/@GrB/private/util/gb_assign.c b/GraphBLAS/@GrB/private/util/gb_assign.c index 6137555b36..a954202089 100644 --- a/GraphBLAS/@GrB/private/util/gb_assign.c +++ b/GraphBLAS/@GrB/private/util/gb_assign.c @@ -21,12 +21,12 @@ // then it is first expanded to an empty matrix of size length(I)-by-length(J), // and G*B_Matrix_*assign is used (not GraphBLAS scalar assignment). -// MATLAB Usage: +// Usage: -// Cout = GrB.assign (Cin, M, accum, A, I, J, desc) -// Cout = GrB.subassign (Cin, M, accum, A, I, J, desc) +// C = gbassign (Cin, M, accum, A, I, J, desc) +// C = gbsubassign (Cin, M, accum, A, I, J, desc) -// Cin, A, and desc are required. See GrB.m for more details. +// Cin and A are required. See GrB.m for more details. #include "gb_matlab.h" @@ -45,7 +45,7 @@ void gb_assign // gbassign or gbsubassign mexFunctions // check inputs //-------------------------------------------------------------------------- - gb_usage (nargin >= 3 && nargin <= 7 && nargout <= 1, usage) ; + gb_usage (nargin >= 2 && nargin <= 7 && nargout <= 2, usage) ; //-------------------------------------------------------------------------- // find the arguments @@ -92,7 +92,7 @@ void gb_assign // gbassign or gbsubassign mexFunctions if (nstrings == 1) { - accum = gb_mxstring_to_binop (String [0], ctype) ; + accum = gb_mxstring_to_binop (String [0], ctype, ctype) ; } //-------------------------------------------------------------------------- @@ -112,6 +112,11 @@ void gb_assign // gbassign or gbsubassign mexFunctions GrB_Index ni = cnrows, nj = cncols ; bool I_allocated = false, J_allocated = false ; + if (cnrows > 1 && cncols > 1 && ncells == 1) + { + ERROR ("linear indexing not yet supported") ; + } + if (cnrows == 1 && ncells == 1) { // only J is present @@ -186,6 +191,7 @@ void gb_assign // gbassign or gbsubassign mexFunctions //-------------------------------------------------------------------------- pargout [0] = gb_export (&C, kind) ; + pargout [1] = mxCreateDoubleScalar (kind) ; GB_WRAPUP ; } diff --git a/GraphBLAS/@GrB/private/util/gb_binop_to_monoid.c b/GraphBLAS/@GrB/private/util/gb_binop_to_monoid.c index 4d9a9dcf44..caf6bf950a 100644 --- a/GraphBLAS/@GrB/private/util/gb_binop_to_monoid.c +++ b/GraphBLAS/@GrB/private/util/gb_binop_to_monoid.c @@ -18,58 +18,107 @@ GrB_Monoid gb_binop_to_monoid // return monoid from a binary op GrB_Monoid monoid ; // MIN monoids: - if (op == GrB_MIN_INT8 ) monoid = GxB_MIN_INT8_MONOID ; - else if (op == GrB_MIN_INT16 ) monoid = GxB_MIN_INT16_MONOID ; - else if (op == GrB_MIN_INT32 ) monoid = GxB_MIN_INT32_MONOID ; - else if (op == GrB_MIN_INT64 ) monoid = GxB_MIN_INT64_MONOID ; - else if (op == GrB_MIN_UINT8 ) monoid = GxB_MIN_UINT8_MONOID ; - else if (op == GrB_MIN_UINT16 ) monoid = GxB_MIN_UINT16_MONOID ; - else if (op == GrB_MIN_UINT32 ) monoid = GxB_MIN_UINT32_MONOID ; - else if (op == GrB_MIN_UINT64 ) monoid = GxB_MIN_UINT64_MONOID ; - else if (op == GrB_MIN_FP32 ) monoid = GxB_MIN_FP32_MONOID ; - else if (op == GrB_MIN_FP64 ) monoid = GxB_MIN_FP64_MONOID ; + if (op == GrB_MIN_INT8 ) monoid = GrB_MIN_MONOID_INT8 ; + else if (op == GrB_MIN_INT16 ) monoid = GrB_MIN_MONOID_INT16 ; + else if (op == GrB_MIN_INT32 ) monoid = GrB_MIN_MONOID_INT32 ; + else if (op == GrB_MIN_INT64 ) monoid = GrB_MIN_MONOID_INT64 ; + else if (op == GrB_MIN_UINT8 ) monoid = GrB_MIN_MONOID_UINT8 ; + else if (op == GrB_MIN_UINT16 ) monoid = GrB_MIN_MONOID_UINT16 ; + else if (op == GrB_MIN_UINT32 ) monoid = GrB_MIN_MONOID_UINT32 ; + else if (op == GrB_MIN_UINT64 ) monoid = GrB_MIN_MONOID_UINT64 ; + else if (op == GrB_MIN_FP32 ) monoid = GrB_MIN_MONOID_FP32 ; + else if (op == GrB_MIN_FP64 ) monoid = GrB_MIN_MONOID_FP64 ; // MAX monoids: - else if (op == GrB_MAX_INT8 ) monoid = GxB_MAX_INT8_MONOID ; - else if (op == GrB_MAX_INT16 ) monoid = GxB_MAX_INT16_MONOID ; - else if (op == GrB_MAX_INT32 ) monoid = GxB_MAX_INT32_MONOID ; - else if (op == GrB_MAX_INT64 ) monoid = GxB_MAX_INT64_MONOID ; - else if (op == GrB_MAX_UINT8 ) monoid = GxB_MAX_UINT8_MONOID ; - else if (op == GrB_MAX_UINT16 ) monoid = GxB_MAX_UINT16_MONOID ; - else if (op == GrB_MAX_UINT32 ) monoid = GxB_MAX_UINT32_MONOID ; - else if (op == GrB_MAX_UINT64 ) monoid = GxB_MAX_UINT64_MONOID ; - else if (op == GrB_MAX_FP32 ) monoid = GxB_MAX_FP32_MONOID ; - else if (op == GrB_MAX_FP64 ) monoid = GxB_MAX_FP64_MONOID ; + else if (op == GrB_MAX_INT8 ) monoid = GrB_MAX_MONOID_INT8 ; + else if (op == GrB_MAX_INT16 ) monoid = GrB_MAX_MONOID_INT16 ; + else if (op == GrB_MAX_INT32 ) monoid = GrB_MAX_MONOID_INT32 ; + else if (op == GrB_MAX_INT64 ) monoid = GrB_MAX_MONOID_INT64 ; + else if (op == GrB_MAX_UINT8 ) monoid = GrB_MAX_MONOID_UINT8 ; + else if (op == GrB_MAX_UINT16 ) monoid = GrB_MAX_MONOID_UINT16 ; + else if (op == GrB_MAX_UINT32 ) monoid = GrB_MAX_MONOID_UINT32 ; + else if (op == GrB_MAX_UINT64 ) monoid = GrB_MAX_MONOID_UINT64 ; + else if (op == GrB_MAX_FP32 ) monoid = GrB_MAX_MONOID_FP32 ; + else if (op == GrB_MAX_FP64 ) monoid = GrB_MAX_MONOID_FP64 ; // PLUS monoids: - else if (op == GrB_PLUS_INT8 ) monoid = GxB_PLUS_INT8_MONOID ; - else if (op == GrB_PLUS_INT16 ) monoid = GxB_PLUS_INT16_MONOID ; - else if (op == GrB_PLUS_INT32 ) monoid = GxB_PLUS_INT32_MONOID ; - else if (op == GrB_PLUS_INT64 ) monoid = GxB_PLUS_INT64_MONOID ; - else if (op == GrB_PLUS_UINT8 ) monoid = GxB_PLUS_UINT8_MONOID ; - else if (op == GrB_PLUS_UINT16) monoid = GxB_PLUS_UINT16_MONOID ; - else if (op == GrB_PLUS_UINT32) monoid = GxB_PLUS_UINT32_MONOID ; - else if (op == GrB_PLUS_UINT64) monoid = GxB_PLUS_UINT64_MONOID ; - else if (op == GrB_PLUS_FP32 ) monoid = GxB_PLUS_FP32_MONOID ; - else if (op == GrB_PLUS_FP64 ) monoid = GxB_PLUS_FP64_MONOID ; + else if (op == GrB_PLUS_INT8 ) monoid = GrB_PLUS_MONOID_INT8 ; + else if (op == GrB_PLUS_INT16 ) monoid = GrB_PLUS_MONOID_INT16 ; + else if (op == GrB_PLUS_INT32 ) monoid = GrB_PLUS_MONOID_INT32 ; + else if (op == GrB_PLUS_INT64 ) monoid = GrB_PLUS_MONOID_INT64 ; + else if (op == GrB_PLUS_UINT8 ) monoid = GrB_PLUS_MONOID_UINT8 ; + else if (op == GrB_PLUS_UINT16) monoid = GrB_PLUS_MONOID_UINT16 ; + else if (op == GrB_PLUS_UINT32) monoid = GrB_PLUS_MONOID_UINT32 ; + else if (op == GrB_PLUS_UINT64) monoid = GrB_PLUS_MONOID_UINT64 ; + else if (op == GrB_PLUS_FP32 ) monoid = GrB_PLUS_MONOID_FP32 ; + else if (op == GrB_PLUS_FP64 ) monoid = GrB_PLUS_MONOID_FP64 ; + + // PLUS monoids for complex: + else if (op == GxB_PLUS_FC32 ) monoid = GxB_PLUS_FC32_MONOID ; + else if (op == GxB_PLUS_FC64 ) monoid = GxB_PLUS_FC64_MONOID ; // TIMES monoids: - else if (op == GrB_TIMES_INT8 ) monoid = GxB_TIMES_INT8_MONOID ; - else if (op == GrB_TIMES_INT16 ) monoid = GxB_TIMES_INT16_MONOID ; - else if (op == GrB_TIMES_INT32 ) monoid = GxB_TIMES_INT32_MONOID ; - else if (op == GrB_TIMES_INT64 ) monoid = GxB_TIMES_INT64_MONOID ; - else if (op == GrB_TIMES_UINT8 ) monoid = GxB_TIMES_UINT8_MONOID ; - else if (op == GrB_TIMES_UINT16) monoid = GxB_TIMES_UINT16_MONOID ; - else if (op == GrB_TIMES_UINT32) monoid = GxB_TIMES_UINT32_MONOID ; - else if (op == GrB_TIMES_UINT64) monoid = GxB_TIMES_UINT64_MONOID ; - else if (op == GrB_TIMES_FP32 ) monoid = GxB_TIMES_FP32_MONOID ; - else if (op == GrB_TIMES_FP64 ) monoid = GxB_TIMES_FP64_MONOID ; + else if (op == GrB_TIMES_INT8 ) monoid = GrB_TIMES_MONOID_INT8 ; + else if (op == GrB_TIMES_INT16 ) monoid = GrB_TIMES_MONOID_INT16 ; + else if (op == GrB_TIMES_INT32 ) monoid = GrB_TIMES_MONOID_INT32 ; + else if (op == GrB_TIMES_INT64 ) monoid = GrB_TIMES_MONOID_INT64 ; + else if (op == GrB_TIMES_UINT8 ) monoid = GrB_TIMES_MONOID_UINT8 ; + else if (op == GrB_TIMES_UINT16) monoid = GrB_TIMES_MONOID_UINT16 ; + else if (op == GrB_TIMES_UINT32) monoid = GrB_TIMES_MONOID_UINT32 ; + else if (op == GrB_TIMES_UINT64) monoid = GrB_TIMES_MONOID_UINT64 ; + else if (op == GrB_TIMES_FP32 ) monoid = GrB_TIMES_MONOID_FP32 ; + else if (op == GrB_TIMES_FP64 ) monoid = GrB_TIMES_MONOID_FP64 ; + + // TIMES monoids for complex: + else if (op == GxB_TIMES_FC32 ) monoid = GxB_TIMES_FC32_MONOID ; + else if (op == GxB_TIMES_FC64 ) monoid = GxB_TIMES_FC64_MONOID ; + + // ANY monoids: + else if (op == GxB_ANY_BOOL ) monoid = GxB_ANY_BOOL_MONOID ; + else if (op == GxB_ANY_INT8 ) monoid = GxB_ANY_INT8_MONOID ; + else if (op == GxB_ANY_INT16 ) monoid = GxB_ANY_INT16_MONOID ; + else if (op == GxB_ANY_INT32 ) monoid = GxB_ANY_INT32_MONOID ; + else if (op == GxB_ANY_INT64 ) monoid = GxB_ANY_INT64_MONOID ; + else if (op == GxB_ANY_UINT8 ) monoid = GxB_ANY_UINT8_MONOID ; + else if (op == GxB_ANY_UINT16) monoid = GxB_ANY_UINT16_MONOID ; + else if (op == GxB_ANY_UINT32) monoid = GxB_ANY_UINT32_MONOID ; + else if (op == GxB_ANY_UINT64) monoid = GxB_ANY_UINT64_MONOID ; + else if (op == GxB_ANY_FP32 ) monoid = GxB_ANY_FP32_MONOID ; + else if (op == GxB_ANY_FP64 ) monoid = GxB_ANY_FP64_MONOID ; + else if (op == GxB_ANY_FC32 ) monoid = GxB_ANY_FC32_MONOID ; + else if (op == GxB_ANY_FC64 ) monoid = GxB_ANY_FC64_MONOID ; // Boolean monoids: - else if (op == GrB_LOR ) monoid = GxB_LOR_BOOL_MONOID ; - else if (op == GrB_LAND ) monoid = GxB_LAND_BOOL_MONOID ; - else if (op == GrB_LXOR ) monoid = GxB_LXOR_BOOL_MONOID ; - else if (op == GrB_EQ_BOOL ) monoid = GxB_EQ_BOOL_MONOID ; + else if (op == GrB_LOR ) monoid = GrB_LOR_MONOID_BOOL ; + else if (op == GrB_LAND ) monoid = GrB_LAND_MONOID_BOOL ; + else if (op == GrB_LXOR ) monoid = GrB_LXOR_MONOID_BOOL ; + // these two operators are identical: + else if (op == GrB_EQ_BOOL || + op == GrB_LXNOR ) monoid = GrB_LXNOR_MONOID_BOOL ; + + // BOR monoids (bitwise or): + else if (op == GrB_BOR_UINT8 ) monoid = GxB_BOR_UINT8_MONOID ; + else if (op == GrB_BOR_UINT16 ) monoid = GxB_BOR_UINT16_MONOID ; + else if (op == GrB_BOR_UINT32 ) monoid = GxB_BOR_UINT32_MONOID ; + else if (op == GrB_BOR_UINT64 ) monoid = GxB_BOR_UINT64_MONOID ; + + // BAND monoids (bitwise and): + else if (op == GrB_BAND_UINT8 ) monoid = GxB_BAND_UINT8_MONOID ; + else if (op == GrB_BAND_UINT16 ) monoid = GxB_BAND_UINT16_MONOID ; + else if (op == GrB_BAND_UINT32 ) monoid = GxB_BAND_UINT32_MONOID ; + else if (op == GrB_BAND_UINT64 ) monoid = GxB_BAND_UINT64_MONOID ; + + // BXOR monoids (bitwise xor): + else if (op == GrB_BXOR_UINT8 ) monoid = GxB_BXOR_UINT8_MONOID ; + else if (op == GrB_BXOR_UINT16 ) monoid = GxB_BXOR_UINT16_MONOID ; + else if (op == GrB_BXOR_UINT32 ) monoid = GxB_BXOR_UINT32_MONOID ; + else if (op == GrB_BXOR_UINT64 ) monoid = GxB_BXOR_UINT64_MONOID ; + + // BXNOR monoids (bitwise xnor): + else if (op == GrB_BXNOR_UINT8 ) monoid = GxB_BXNOR_UINT8_MONOID ; + else if (op == GrB_BXNOR_UINT16 ) monoid = GxB_BXNOR_UINT16_MONOID ; + else if (op == GrB_BXNOR_UINT32 ) monoid = GxB_BXNOR_UINT32_MONOID ; + else if (op == GrB_BXNOR_UINT64 ) monoid = GxB_BXNOR_UINT64_MONOID ; else { diff --git a/GraphBLAS/@GrB/private/util/gb_by_col.c b/GraphBLAS/@GrB/private/util/gb_by_col.c index cf1807e346..34c8300cb2 100644 --- a/GraphBLAS/@GrB/private/util/gb_by_col.c +++ b/GraphBLAS/@GrB/private/util/gb_by_col.c @@ -30,6 +30,7 @@ GrB_Matrix gb_by_col // return the matrix by column // make a deep copy of A_input and change it to be stored by column OK (GrB_Matrix_dup (&A_copy, A_input)) ; OK (GxB_Matrix_Option_set (A_copy, GxB_FORMAT, GxB_BY_COL)) ; + OK (GrB_Matrix_wait (&A_copy)) ; A = A_copy ; } else @@ -38,10 +39,6 @@ GrB_Matrix gb_by_col // return the matrix by column A = A_input ; } - // make sure A is finalized - GrB_Index anz ; - OK (GrB_Matrix_nvals (&anz, A)) ; - // return results (*A_copy_handle) = A_copy ; return (A) ; diff --git a/GraphBLAS/@GrB/private/util/gb_default_type.c b/GraphBLAS/@GrB/private/util/gb_default_type.c new file mode 100644 index 0000000000..5b4ff88883 --- /dev/null +++ b/GraphBLAS/@GrB/private/util/gb_default_type.c @@ -0,0 +1,189 @@ +//------------------------------------------------------------------------------ +// gb_default_type: determine the default type for a binary operator +//------------------------------------------------------------------------------ + +// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. +// http://suitesparse.com See GraphBLAS/Doc/License.txt for license. + +//------------------------------------------------------------------------------ + +// When a binary operator has inputs A and B, with no type specified, the type +// is determined from the types of A and B. + +// If A or B are boolean, the type is taken from the other operand. +// If either A or B are signed, then the type is signed. + +#include "gb_matlab.h" + +GrB_Type gb_default_type // return the default type to use +( + const GrB_Type atype, // type of the A matrix + const GrB_Type btype // type of the B matrix +) +{ + + if (atype == NULL || btype == NULL) + { + + // undefined type + return (NULL) ; + + } + else if (atype == GrB_BOOL) + { + + // A is bool: optype determined by B + return (btype) ; + + } + else if (btype == GrB_BOOL) + { + + // B is bool: optype determined by A + return (atype) ; + + } + else if (atype == GrB_INT8) + { + + // A is int8: optype must be signed, and at least 8 bits + if (btype == GrB_UINT8 ) return (GrB_INT8) ; + if (btype == GrB_UINT16 ) return (GrB_INT16) ; + if (btype == GrB_UINT32 ) return (GrB_INT32) ; + if (btype == GrB_UINT64 ) return (GrB_INT64) ; + return (btype) ; + + } + else if (atype == GrB_INT16) + { + + // A is int16: optype must be signed, and at least 16 bits + if (btype == GrB_INT8 || + btype == GrB_UINT8 || + btype == GrB_UINT16 ) return (GrB_INT16) ; + if (btype == GrB_UINT32 ) return (GrB_INT32) ; + if (btype == GrB_UINT64 ) return (GrB_INT64) ; + return (btype) ; + + } + else if (atype == GrB_INT32) + { + + // A is int32: optype must be signed, and at least 32 bits + if (btype == GrB_INT8 || + btype == GrB_INT16 || + btype == GrB_UINT8 || + btype == GrB_UINT16 || + btype == GrB_UINT32 ) return (GrB_INT32) ; + if (btype == GrB_UINT64 ) return (GrB_INT64) ; + return (btype) ; + + } + else if (atype == GrB_INT64) + { + + // A is int64: optype must be signed, and at least 64 + // bits (if integer). float and float complex are OK + if (btype == GrB_INT8 || + btype == GrB_INT16 || + btype == GrB_INT32 || + btype == GrB_UINT8 || + btype == GrB_UINT16 || + btype == GrB_UINT32 || + btype == GrB_UINT64 ) return (GrB_INT64) ; + return (btype) ; + + } + else if (atype == GrB_UINT8) + { + + // A is uint8: optype determined by B (which is not bool; see above) + return (btype) ; + + } + else if (atype == GrB_UINT16) + { + + // A is uint16: optype can be unsigned if B is also unsigned. + // optype must be at least 16 bits. + if (btype == GrB_UINT8 ) return (GrB_UINT16) ; + if (btype == GrB_INT8 ) return (GrB_INT16) ; + return (btype) ; + + } + else if (atype == GrB_UINT32) + { + + // A is uint32: optype can be unsigned if B is also unsigned. + // optype must be at least 32 bits. + if (btype == GrB_UINT8 || + btype == GrB_UINT16 ) return (GrB_UINT32) ; + if (btype == GrB_INT8 || + btype == GrB_INT16 ) return (GrB_INT32) ; + return (btype) ; + + } + else if (atype == GrB_UINT64) + { + + // A is uint64: optype can be unsigned if B is also unsigned. + // optype must be at least 64 bits. float and float complex OK. + if (btype == GrB_UINT8 || + btype == GrB_UINT16 || + btype == GrB_UINT32 ) return (GrB_UINT64) ; + if (btype == GrB_INT8 || + btype == GrB_INT16 || + btype == GrB_INT32 ) return (GrB_INT64) ; + return (btype) ; + + } + else if (atype == GrB_FP32) + { + + // A is float: optype must be real or complex + if (btype == GrB_INT8 || + btype == GrB_INT16 || + btype == GrB_INT32 || + btype == GrB_INT64 || + btype == GrB_UINT8 || + btype == GrB_UINT16 || + btype == GrB_UINT32 || + btype == GrB_UINT64 ) return (GrB_FP32) ; + return (btype) ; + + } + else if (atype == GrB_FP64) + { + + // A is double: optype must be double or double complex + if (btype == GxB_FC32 || + btype == GxB_FC64 ) return (GxB_FC64) ; + return (GrB_FP64) ; + + } + else if (atype == GxB_FC32) + { + + // A is float complex: optype must be float complex + // or double complex + if (btype == GrB_FP64 || + btype == GxB_FC64 ) return (GxB_FC64) ; + return (GxB_FC32) ; + + } + else if (atype == GxB_FC64) + { + + // A is double complex: optype must be double complex + return (GxB_FC64) ; + + } + else + { + + // unknown type + return (NULL) ; + + } +} + diff --git a/GraphBLAS/@GrB/private/util/gb_export_to_mxfull.c b/GraphBLAS/@GrB/private/util/gb_export_to_mxfull.c index 4f09de2b62..e6035b88ea 100644 --- a/GraphBLAS/@GrB/private/util/gb_export_to_mxfull.c +++ b/GraphBLAS/@GrB/private/util/gb_export_to_mxfull.c @@ -37,7 +37,7 @@ mxArray *gb_export_to_mxfull // return exported MATLAB dense matrix F mxArray *F ; void *X = (*X_handle) ; if (X == NULL) - { + { // A GrB_Matrix C has a null C->x array, if C has no entries. Since // C has already been expanded to a full matrix, C->x can be NULL // only if nrows or ncols is zero. @@ -48,7 +48,7 @@ mxArray *gb_export_to_mxfull // return exported MATLAB dense matrix F if (type == GrB_BOOL) { F = mxCreateLogicalMatrix (0, 0) ; - mxSetData (F, X) ; + mxSetData (F, X) ; // OK:bool } else if (type == GrB_FP32) { @@ -100,13 +100,16 @@ mxArray *gb_export_to_mxfull // return exported MATLAB dense matrix F F = mxCreateNumericMatrix (0, 0, mxUINT64_CLASS, mxREAL) ; mxSetUint64s (F, X) ; } - #ifdef GB_COMPLEX_TYPE - else if (type == gb_complex_type) + else if (type == GxB_FC32) + { + F = mxCreateNumericMatrix (0, 0, mxSINGLE_CLASS, mxCOMPLEX) ; + mxSetComplexSingles (F, X) ; + } + else if (type == GxB_FC64) { F = mxCreateNumericMatrix (0, 0, mxDOUBLE_CLASS, mxCOMPLEX) ; - mxSetComplexDouble (F, X) ; + mxSetComplexDoubles (F, X) ; } - #endif else { ERROR ("unsupported type") ; diff --git a/GraphBLAS/@GrB/private/util/gb_export_to_mxsparse.c b/GraphBLAS/@GrB/private/util/gb_export_to_mxsparse.c index 2723c81d30..d474e0d7b3 100644 --- a/GraphBLAS/@GrB/private/util/gb_export_to_mxsparse.c +++ b/GraphBLAS/@GrB/private/util/gb_export_to_mxsparse.c @@ -36,11 +36,8 @@ mxArray *gb_export_to_mxsparse // return exported MATLAB sparse matrix S GxB_Format_Value fmt ; OK (GxB_Matrix_Option_get (*A_handle, GxB_FORMAT, &fmt)) ; - if (fmt == GxB_BY_COL && (type == GrB_BOOL || type == GrB_FP64 - #ifdef GB_COMPLEX_TYPE - || type == gb_complex_type - #endif - )) + if (fmt == GxB_BY_COL && + (type == GrB_BOOL || type == GrB_FP64 || type == GxB_FC64)) { //---------------------------------------------------------------------- @@ -65,15 +62,32 @@ mxArray *gb_export_to_mxsparse // return exported MATLAB sparse matrix S { //---------------------------------------------------------------------- - // typecast A to double, and format by column + // typecast A to logical, double or double complex, and format by column //---------------------------------------------------------------------- // MATLAB supports only logical, double, and double complex sparse - // matrices. These correspond to GrB_BOOL, GrB_FP64, and - // gb_complex_type, respectively. A is typecasted to double, and - // converted to CSC format if not already in that format. + // matrices. These correspond to GrB_BOOL, GrB_FP64, and GxB_FC64, + // respectively. A is typecasted to logical, double or double complex, + // and converted to CSC format if not already in that format. + + if (type == GxB_FC32 || type == GxB_FC64) + { + // typecast to double complex, by col + type = GxB_FC64 ; + } + else if (type == GrB_BOOL) + { + // typecast to logical, by col + type = GrB_BOOL ; + } + else + { + // typecast to double, by col + type = GrB_FP64 ; + } + + T = gb_typecast (type, GxB_BY_COL, *A_handle) ; - T = gb_typecast (GrB_FP64, GxB_BY_COL, *A_handle) ; OK (GrB_Matrix_free (A_handle)) ; } @@ -108,12 +122,10 @@ mxArray *gb_export_to_mxsparse // return exported MATLAB sparse matrix S { S = mxCreateSparseLogicalMatrix (nrows, ncols, 1) ; } - #ifdef GB_COMPLEX_TYPE - else if (type == gb_complex_type) - { + else if (type == GxB_FC64) + { S = mxCreateSparse (nrows, ncols, 1, mxCOMPLEX) ; } - #endif else { S = mxCreateSparse (nrows, ncols, 1, mxREAL) ; @@ -146,13 +158,11 @@ mxArray *gb_export_to_mxsparse // return exported MATLAB sparse matrix S { S = mxCreateSparseLogicalMatrix (0, 0, 1) ; } - #ifdef GB_COMPLEX_TYPE - else if (type == gb_complex_type) - { + else if (type == GxB_FC64) + { S = mxCreateSparse (0, 0, 1, mxCOMPLEX) ; } - #endif - else + else // type == GrB_FP64 { S = mxCreateSparse (0, 0, 1, mxREAL) ; } @@ -175,19 +185,17 @@ mxArray *gb_export_to_mxsparse // return exported MATLAB sparse matrix S // set the values if (type == GrB_BOOL) { - p = mxGetData (S) ; + p = mxGetData (S) ; // OK:bool gb_mxfree (&p) ; - mxSetData (S, Tx) ; + mxSetData (S, Tx) ; // OK:bool } - #ifdef GB_COMPLEX_TYPE - else if (type == gb_complex_type) - { + else if (type == GxB_FC64) + { p = mxGetComplexDoubles (S) ; gb_mxfree (&p) ; mxSetComplexDoubles (S, Tx) ; } - #endif - else + else // type == GrB_FP64 { p = mxGetDoubles (S) ; gb_mxfree (&p) ; diff --git a/GraphBLAS/@GrB/private/util/gb_export_to_mxstruct.c b/GraphBLAS/@GrB/private/util/gb_export_to_mxstruct.c index 6fefa749d6..294b3760e2 100644 --- a/GraphBLAS/@GrB/private/util/gb_export_to_mxstruct.c +++ b/GraphBLAS/@GrB/private/util/gb_export_to_mxstruct.c @@ -18,7 +18,8 @@ static const char *MatrixFields [NFIELDS] = { - "GraphBLAS", // 0: "logical", "int8", ... "double", "complex" + "GraphBLAS", // 0: "logical", "int8", ... "double", + // "single complex", or "double complex" "s", // 1: all scalar info goes here "p", // 2: array of int64_t, size plen+1 "i", // 3: array of int64_t, size nzmax @@ -60,7 +61,7 @@ mxArray *gb_export_to_mxstruct // return exported MATLAB struct G // export content into the output struct //-------------------------------------------------------------------------- - // export the GraphBLAS type + // export the GraphBLAS type as a string mxSetFieldByNumber (G, 0, 0, gb_type_to_mxstring (A->type)) ; // export the scalar content diff --git a/GraphBLAS/@GrB/private/util/gb_first_binop.c b/GraphBLAS/@GrB/private/util/gb_first_binop.c index 67695d2a44..d9f9fb711e 100644 --- a/GraphBLAS/@GrB/private/util/gb_first_binop.c +++ b/GraphBLAS/@GrB/private/util/gb_first_binop.c @@ -26,12 +26,8 @@ GrB_BinaryOp gb_first_binop // return GrB_FIRST_[type] operator else if (type == GrB_UINT64) return (GrB_FIRST_UINT64) ; else if (type == GrB_FP32) return (GrB_FIRST_FP32) ; else if (type == GrB_FP64) return (GrB_FIRST_FP64) ; - #ifdef GB_COMPLEX_TYPE - else if (type == gb_complex_type) - { - return (gb_first_complex) ; - } - #endif + else if (type == GxB_FC32) return (GxB_FIRST_FC32) ; + else if (type == GxB_FC64) return (GxB_FIRST_FC64) ; else { ERROR ("unsupported type") ; diff --git a/GraphBLAS/@GrB/private/util/gb_get_format.c b/GraphBLAS/@GrB/private/util/gb_get_format.c index 052c52be69..87764c688d 100644 --- a/GraphBLAS/@GrB/private/util/gb_get_format.c +++ b/GraphBLAS/@GrB/private/util/gb_get_format.c @@ -11,8 +11,8 @@ // computed from one or two input matrices A and B. The following rules are // used, in order: -// (1) GraphBLAS operations of the form Cout = GrB.method (Cin, ...) use the -// format of Cin for the new matrix Cout. +// (1) GraphBLAS operations of the form C = GrB.method (Cin, ...) use the +// format of Cin for the new matrix C. // (1) If the format is determined by the descriptor to the method, then that // determines the format of C. @@ -21,11 +21,11 @@ // (3) If C is a row vector (cnrows == 1) then C is stored by row. -// (4) If A is present, and not a row or column vector, then its format is used -// for C. +// (4) If A is present, and not a row or column vector or scalar, then its +// format is used for C. -// (5) If B is present, and not a row or column vector, then its format is used -// for C. +// (5) If B is present, and not a row or column vector or scalar, then its +// format is used for C. // (6) Otherwise, the global default format is used for C. diff --git a/GraphBLAS/@GrB/private/util/gb_get_mxargs.c b/GraphBLAS/@GrB/private/util/gb_get_mxargs.c index ce33317300..2918361d50 100644 --- a/GraphBLAS/@GrB/private/util/gb_get_mxargs.c +++ b/GraphBLAS/@GrB/private/util/gb_get_mxargs.c @@ -9,11 +9,11 @@ // gb_get_mxargs collects all the input arguments for the 12 foundational // GraphBLAS operations. The user-level view is described below. For -// the private mexFunctions, the descriptor always appears as the last +// the private mexFunctions, the descriptor optionally appears as the last // argument. The matrix arguments are either MATLAB sparse or full matrices, // GraphBLAS matrices. To call the mexFunction, the opaque content of the // GraphBLAS matrices has been extracted, so they appear here as GraphBLAS -// structs. +// structs (a MATLAB struct G whose first field is always G.GraphBLAS). #include "gb_matlab.h" @@ -23,7 +23,6 @@ void gb_get_mxargs int nargin, // # input arguments for mexFunction const mxArray *pargin [ ], // input arguments for mexFunction const char *usage, // usage to print, if too many args appear - // output: const mxArray *Matrix [4], // matrix arguments int *nmatrices, // # of matrix arguments @@ -39,10 +38,22 @@ void gb_get_mxargs { //-------------------------------------------------------------------------- - // get the descriptor + // find the descriptor //-------------------------------------------------------------------------- - (*desc) = gb_mxarray_to_descriptor (pargin [nargin-1], kind, fmt, base) ; + (*desc) = NULL ; + (*kind) = KIND_GRB ; + (*fmt) = GxB_NO_FORMAT ; + (*base) = BASE_DEFAULT ; + if (nargin > 0) + { + (*desc) = gb_mxarray_to_descriptor (pargin [nargin-1], kind, fmt, base); + } + if ((*desc) != NULL) + { + // descriptor is present, remove it from further consideration + nargin-- ; + } //-------------------------------------------------------------------------- // find the remaining arguments @@ -52,7 +63,7 @@ void gb_get_mxargs (*nstrings) = 0 ; (*ncells) = 0 ; - for (int k = 0 ; k < (nargin-1) ; k++) + for (int k = 0 ; k < nargin ; k++) { if (mxIsCell (pargin [k])) { diff --git a/GraphBLAS/@GrB/private/util/gb_get_shallow.c b/GraphBLAS/@GrB/private/util/gb_get_shallow.c index 19720d3abe..c6edc7f923 100644 --- a/GraphBLAS/@GrB/private/util/gb_get_shallow.c +++ b/GraphBLAS/@GrB/private/util/gb_get_shallow.c @@ -171,65 +171,74 @@ GrB_Matrix gb_get_shallow // return a shallow copy of MATLAB sparse matrix // MATLAB sparse or dense double matrix Xx = mxGetDoubles (X) ; } - #ifdef GB_COMPLEX_TYPE - else if (type == gb_complex_type) - { + else if (type == GxB_FC64) + { // MATLAB sparse or dense double complex matrix Xx = mxGetComplexDoubles (X) ; } - #endif else if (type == GrB_BOOL) { // MATLAB sparse or dense logical matrix - Xx = mxGetData (X) ; + Xx = mxGetData (X) ; // OK:bool } - else + else if (X_is_sparse) { // MATLAB does not support any other kinds of sparse matrices - if (X_is_sparse) - { - ERROR ("unsupported type") ; - } - else if (type == GrB_INT8) - { - Xx = mxGetInt8s (X) ; - } - else if (type == GrB_INT16) - { - Xx = mxGetInt16s (X) ; - } - else if (type == GrB_INT32) - { - Xx = mxGetInt32s (X) ; - } - else if (type == GrB_INT64) - { - Xx = mxGetInt64s (X) ; - } - else if (type == GrB_UINT8) - { - Xx = mxGetUint8s (X) ; - } - else if (type == GrB_UINT16) - { - Xx = mxGetUint16s (X) ; - } - else if (type == GrB_UINT32) - { - Xx = mxGetUint32s (X) ; - } - else if (type == GrB_UINT64) - { - Xx = mxGetUint64s (X) ; - } - else if (type == GrB_FP32) - { - Xx = mxGetSingles (X) ; - } - else - { - ERROR ("unsupported type") ; - } + ERROR ("unsupported type") ; + } + else if (type == GrB_INT8) + { + // dense int8 matrix + Xx = mxGetInt8s (X) ; + } + else if (type == GrB_INT16) + { + // dense int16 matrix + Xx = mxGetInt16s (X) ; + } + else if (type == GrB_INT32) + { + // dense int32 matrix + Xx = mxGetInt32s (X) ; + } + else if (type == GrB_INT64) + { + // dense int64 matrix + Xx = mxGetInt64s (X) ; + } + else if (type == GrB_UINT8) + { + // dense uint8 matrix + Xx = mxGetUint8s (X) ; + } + else if (type == GrB_UINT16) + { + // dense uint16 matrix + Xx = mxGetUint16s (X) ; + } + else if (type == GrB_UINT32) + { + // dense uint32 matrix + Xx = mxGetUint32s (X) ; + } + else if (type == GrB_UINT64) + { + // dense uint64 matrix + Xx = mxGetUint64s (X) ; + } + else if (type == GrB_FP32) + { + // dense single matrix + Xx = mxGetSingles (X) ; + } + else if (type == GxB_FC32) + { + // dense single complex matrix + Xx = mxGetComplexSingles (X) ; + } + else + { + ERROR ("unsupported type") ; } // import the matrix in CSC format. This sets Xp, Xi, and Xx to NULL, diff --git a/GraphBLAS/@GrB/private/util/gb_is_all.c b/GraphBLAS/@GrB/private/util/gb_is_all.c index 898999c4ce..5f9caee40c 100644 --- a/GraphBLAS/@GrB/private/util/gb_is_all.c +++ b/GraphBLAS/@GrB/private/util/gb_is_all.c @@ -63,7 +63,7 @@ bool gb_is_all // true if op (A,B) is all true, false otherwise OK (GxB_Matrix_Option_get (A, GxB_FORMAT, &fmt)) ; OK (GxB_Matrix_Option_set (C, GxB_FORMAT, fmt)) ; - OK (GrB_eWiseMult_Matrix_BinaryOp (C, NULL, NULL, op, A, B, NULL)) ; + OK (GrB_Matrix_eWiseMult_BinaryOp (C, NULL, NULL, op, A, B, NULL)) ; // ensure C has the same number of entries as A and B OK (GrB_Matrix_nvals (&nvals, C)) ; @@ -76,7 +76,7 @@ bool gb_is_all // true if op (A,B) is all true, false otherwise // result = and (C) bool result = true ; - OK (GrB_Matrix_reduce_BOOL (&result, NULL, GxB_LAND_BOOL_MONOID, C, NULL)) ; + OK (GrB_Matrix_reduce_BOOL (&result, NULL, GrB_LAND_MONOID_BOOL, C, NULL)) ; // free workspace and return result GrB_Matrix_free (&C) ; diff --git a/GraphBLAS/@GrB/private/util/gb_is_equal.c b/GraphBLAS/@GrB/private/util/gb_is_equal.c index 2964ba14f5..98c3426431 100644 --- a/GraphBLAS/@GrB/private/util/gb_is_equal.c +++ b/GraphBLAS/@GrB/private/util/gb_is_equal.c @@ -10,8 +10,8 @@ // gb_is_equal checks if two matrices are identically equal (same size, // type, pattern, size, and values). -// If the two matrices are GrB_FP32, GrB_FP64, or gb_complex_type (in the -// future), and have NaNs, then gb_is_equal returns false, since NaN == NaN is +// If the two matrices are GrB_FP32, GrB_FP64, GxB_FC32, or GxB_FC64, +// and have NaNs, then gb_is_equal returns false, since NaN == NaN is // false. To check for NaN equality (like isequaln in MATLAB), use gb_is_all // with a user-defined operator f(x,y) that returns true if x and y are equal, // or if both are NaN, and false otherwise. @@ -48,9 +48,8 @@ bool gb_is_equal // true if A == B, false if A ~= B else if (atype == GrB_UINT64) op = GrB_EQ_UINT64 ; else if (atype == GrB_FP32 ) op = GrB_EQ_FP32 ; else if (atype == GrB_FP64 ) op = GrB_EQ_FP64 ; - #ifdef GB_COMPLEX_TYPE - else if (atype == gb_complex_type) op = ... ; - #endif + else if (atype == GxB_FC32 ) op = GxB_EQ_FC32 ; + else if (atype == GxB_FC64 ) op = GxB_EQ_FC64 ; else { ERROR ("unsupported type") ; diff --git a/GraphBLAS/@GrB/private/util/gb_is_float.c b/GraphBLAS/@GrB/private/util/gb_is_float.c new file mode 100644 index 0000000000..23c713b936 --- /dev/null +++ b/GraphBLAS/@GrB/private/util/gb_is_float.c @@ -0,0 +1,19 @@ +//------------------------------------------------------------------------------ +// gb_is_float: check if a GrB_Type is floating-point +//------------------------------------------------------------------------------ + +// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. +// http://suitesparse.com See GraphBLAS/Doc/License.txt for license. + +//------------------------------------------------------------------------------ + +#include "gb_matlab.h" + +bool gb_is_float (const GrB_Type type) +{ + return ((type == GrB_FP32 ) || + (type == GrB_FP64 ) || + (type == GxB_FC32 ) || + (type == GxB_FC64 )) ; +} + diff --git a/GraphBLAS/@GrB/private/util/gb_is_integer.c b/GraphBLAS/@GrB/private/util/gb_is_integer.c new file mode 100644 index 0000000000..4f3838cb35 --- /dev/null +++ b/GraphBLAS/@GrB/private/util/gb_is_integer.c @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// gb_is_integer: check if a GrB_Type is integer +//------------------------------------------------------------------------------ + +// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. +// http://suitesparse.com See GraphBLAS/Doc/License.txt for license. + +//------------------------------------------------------------------------------ + +#include "gb_matlab.h" + +bool gb_is_integer (const GrB_Type type) +{ + return ((type == GrB_INT8 ) || + (type == GrB_INT16 ) || + (type == GrB_INT32 ) || + (type == GrB_INT64 ) || + (type == GrB_UINT8 ) || + (type == GrB_UINT16) || + (type == GrB_UINT32) || + (type == GrB_UINT64)) ; +} + diff --git a/GraphBLAS/@GrB/private/util/gb_matlab.h b/GraphBLAS/@GrB/private/util/gb_matlab.h index 9522041f72..3a20d656b0 100644 --- a/GraphBLAS/@GrB/private/util/gb_matlab.h +++ b/GraphBLAS/@GrB/private/util/gb_matlab.h @@ -172,7 +172,7 @@ GrB_Matrix gb_typecast // A = (type) S, where A is deep GrB_Matrix S // may be shallow ) ; -void gb_abort ( void ) ; // assertion failure +void gb_abort ( void ) ; // failure int gb_flush ( void ) ; // flush mexPrintf output to MATLAB Command Window @@ -214,13 +214,15 @@ GrB_UnaryOp gb_string_and_type_to_unop // return op from string and type GrB_BinaryOp gb_mxstring_to_binop // return binary operator from a string ( const mxArray *mxstring, // MATLAB string - const GrB_Type default_type // default type if not in the string + const GrB_Type atype, // type of A + const GrB_Type btype // type of B ) ; GrB_BinaryOp gb_string_to_binop // return binary operator from a string ( char *opstring, // string defining the operator - const GrB_Type default_type // default type if not in the string + const GrB_Type atype, // type of A + const GrB_Type btype // type of B ) ; GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type @@ -232,14 +234,15 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type GrB_Semiring gb_mxstring_to_semiring // return semiring from a string ( const mxArray *mxstring, // MATLAB string - const GrB_Type default_type // default type if not in the string + const GrB_Type atype, // type of A + const GrB_Type btype // type of B ) ; GrB_Semiring gb_string_to_semiring // return a semiring from a string ( char *semiring_string, // string defining the semiring - const GrB_Type default_type // default type if not in the string: - // type of x,y inputs to mult operator + const GrB_Type atype, // type of A + const GrB_Type btype // type of B ) ; GrB_Semiring gb_semiring // built-in semiring, or NULL if error @@ -248,9 +251,9 @@ GrB_Semiring gb_semiring // built-in semiring, or NULL if error const GrB_BinaryOp mult // multiply operator ) ; -GrB_Descriptor gb_mxarray_to_descriptor // return a new descriptor +GrB_Descriptor gb_mxarray_to_descriptor // new descriptor, or NULL if none ( - const mxArray *D_matlab, // MATLAB struct + const mxArray *desc_matlab, // MATLAB struct with possible descriptor kind_enum_t *kind, // GrB, sparse, or full GxB_Format_Value *fmt, // by row or by col base_enum_t *base // 0-based int, 1-based int, or 1-based double @@ -341,13 +344,13 @@ GrB_Monoid gb_binop_to_monoid // return monoid from a binary op GrB_Monoid gb_string_to_monoid // return monoid from a string ( char *opstring, // string defining the operator - const GrB_Type default_type // default type if not in the string + const GrB_Type type // default type if not in the string ) ; GrB_Monoid gb_mxstring_to_monoid // return monoid from a string ( const mxArray *mxstring, // MATLAB string - const GrB_Type default_type // default type if not in the string + const GrB_Type type // default type if not in the string ) ; GxB_Format_Value gb_mxstring_to_format // GxB_BY_ROW or GxB_BY_COL @@ -373,7 +376,7 @@ void gb_assign // gbassign or gbsubassign mexFunctions ( int nargout, // # output arguments for mexFunction mxArray *pargout [ ], // output arguments for mexFunction - int nargin, // # inpu arguments for mexFunction + int nargin, // # input arguments for mexFunction const mxArray *pargin [ ], // input arguments for mexFunction bool do_subassign, // true: do subassign, false: do assign const char *usage // usage string to print if error @@ -430,13 +433,24 @@ bool gb_isnotnan32 (GrB_Index i, GrB_Index j, GrB_Index nrows, GrB_Index ncols, bool gb_isnotnan64 (GrB_Index i, GrB_Index j, GrB_Index nrows, GrB_Index ncols, const void *x, const void *b) ; +bool gb_isnanfc32 (GrB_Index i, GrB_Index j, GrB_Index nrows, + GrB_Index ncols, const void *x, const void *b) ; + +bool gb_isnanfc64 (GrB_Index i, GrB_Index j, GrB_Index nrows, + GrB_Index ncols, const void *x, const void *b) ; + +bool gb_isnotnanfc32 (GrB_Index i, GrB_Index j, GrB_Index nrows, + GrB_Index ncols, const void *x, const void *b) ; + +bool gb_isnotnanfc64 (GrB_Index i, GrB_Index j, GrB_Index nrows, + GrB_Index ncols, const void *x, const void *b) ; + void gb_get_mxargs ( // input: int nargin, // # input arguments for mexFunction const mxArray *pargin [ ], // input arguments for mexFunction const char *usage, // usage to print, if too many args appear - // output: const mxArray *Matrix [4], // matrix arguments int *nmatrices, // # of matrix arguments @@ -458,5 +472,19 @@ double gb_norm // compute norm (A,kind) int64_t norm_kind // 0, 1, 2, INT64_MAX, or INT64_MIN ) ; +GrB_Type gb_default_type // return the default type to use +( + const GrB_Type atype, // type of the A matrix + const GrB_Type btype // type of the B matrix +) ; + +bool gb_is_integer (const GrB_Type type) ; + +bool gb_is_float (const GrB_Type type) ; + +GrB_BinaryOp gb_round_binop (const GrB_Type type) ; + +mxArray *gb_mxclass_to_mxstring (mxClassID class, bool is_complex) ; + #endif diff --git a/GraphBLAS/@GrB/private/util/gb_matrix_assign_scalar.c b/GraphBLAS/@GrB/private/util/gb_matrix_assign_scalar.c index 5948932bae..a103484f97 100644 --- a/GraphBLAS/@GrB/private/util/gb_matrix_assign_scalar.c +++ b/GraphBLAS/@GrB/private/util/gb_matrix_assign_scalar.c @@ -13,7 +13,7 @@ // if do_subassign false: GrB_Matrix_assign_[TYPE] // The input scalar is held as A(0,0) in a GrB_Matrix A. If A(0,0) is not -// present, the value zero is used. +// present in A, the value zero is used. void gb_matrix_assign_scalar ( @@ -175,21 +175,32 @@ void gb_matrix_assign_scalar OK (GrB_Matrix_assign_FP64 (C, M, op, x, I, ni, J, nj, desc)) ; } } - #ifdef GB_COMPLEX_TYPE - else if (atype == gb_complex_type) + else if (atype == GxB_FC32) { - double complex x = 0 ; - OK2 (GrB_Matrix_extractElement_UDT (&x, A, 0, 0)) ; + GxB_FC32_t x = GxB_CMPLXF (0,0) ; + OK2 (GxB_Matrix_extractElement_FC32 (&x, A, 0, 0)) ; if (do_subassign) - { - OK (GxB_Matrix_subassign_UDT (C, M, op, &x, I, ni, J, nj, desc)) ; + { + OK (GxB_Matrix_subassign_FC32 (C, M, op, x, I, ni, J, nj, desc)) ; + } + else + { + OK (GxB_Matrix_assign_FC32 (C, M, op, x, I, ni, J, nj, desc)) ; + } + } + else if (atype == GxB_FC64) + { + GxB_FC64_t x = GxB_CMPLX (0,0) ; + OK2 (GxB_Matrix_extractElement_FC64 (&x, A, 0, 0)) ; + if (do_subassign) + { + OK (GxB_Matrix_subassign_FC64 (C, M, op, x, I, ni, J, nj, desc)) ; } else - { - OK (GrB_Matrix_assign_UDT (C, M, op, &x, I, ni, J, nj, desc)) ; + { + OK (GxB_Matrix_assign_FC64 (C, M, op, x, I, ni, J, nj, desc)) ; } } - #endif else { ERROR ("unsupported type") ; diff --git a/GraphBLAS/@GrB/private/util/gb_mxarray_to_descriptor.c b/GraphBLAS/@GrB/private/util/gb_mxarray_to_descriptor.c index 148dd9091f..1dae9fac5d 100644 --- a/GraphBLAS/@GrB/private/util/gb_mxarray_to_descriptor.c +++ b/GraphBLAS/@GrB/private/util/gb_mxarray_to_descriptor.c @@ -15,20 +15,20 @@ static void get_descriptor ( - GrB_Descriptor D, // GraphBLAS descriptor to modify - const mxArray *D_matlab, // MATLAB struct with d.out, etc - const char *fieldname, // fieldname to extract from D_matlab - const GrB_Desc_Field field // field to set in D + GrB_Descriptor desc, // GraphBLAS descriptor to modify + const mxArray *desc_matlab, // MATLAB struct with d.out, etc + const char *fieldname, // fieldname to extract from desc_matlab + const GrB_Desc_Field field // field to set in desc ) { // find the field in the MATLAB struct - int fieldnumber = mxGetFieldNumber (D_matlab, fieldname) ; + int fieldnumber = mxGetFieldNumber (desc_matlab, fieldname) ; if (fieldnumber >= 0) { // the field is present - mxArray *value = mxGetFieldByNumber (D_matlab, 0, fieldnumber) ; + mxArray *value = mxGetFieldByNumber (desc_matlab, 0, fieldnumber) ; if (MATCH (fieldname, "nthreads")) { @@ -37,7 +37,7 @@ static void get_descriptor CHECK_ERROR (!gb_mxarray_is_scalar (value), "d.nthreads must be a scalar") ; int nthreads_max = (int) mxGetScalar (value) ; - OK (GxB_Desc_set (D, GxB_NTHREADS, nthreads_max)) ; + OK (GxB_Desc_set (desc, GxB_NTHREADS, nthreads_max)) ; } else if (MATCH (fieldname, "chunk")) @@ -47,7 +47,7 @@ static void get_descriptor CHECK_ERROR (!gb_mxarray_is_scalar (value), "d.chunk must be a scalar") ; double chunk = mxGetScalar (value) ; - OK (GxB_Desc_set (D, GxB_CHUNK, chunk)) ; + OK (GxB_Desc_set (desc, GxB_CHUNK, chunk)) ; } else @@ -60,47 +60,47 @@ static void get_descriptor // convert the string to a Descriptor value, and set the value if (MATCH (s, "default")) { - OK (GxB_Desc_set (D, field, GxB_DEFAULT)) ; + OK (GxB_Desc_set (desc, field, GxB_DEFAULT)) ; } else if (MATCH (s, "transpose")) { - OK (GxB_Desc_set (D, field, GrB_TRAN)) ; + OK (GxB_Desc_set (desc, field, GrB_TRAN)) ; } - else if (MATCH (s, "complement") || MATCH (s, "comp")) + else if (MATCH (s, "complement")) { - OK (GxB_Desc_set (D, field, GrB_COMP)) ; + OK (GxB_Desc_set (desc, field, GrB_COMP)) ; } else if (MATCH (s, "structure") || MATCH (s, "structural")) { - OK (GxB_Desc_set (D, field, GrB_STRUCTURE)) ; + OK (GxB_Desc_set (desc, field, GrB_STRUCTURE)) ; } else if (MATCH (s, "structural complement")) { - OK (GxB_Desc_set (D, field, GrB_COMP + GrB_STRUCTURE)) ; + OK (GxB_Desc_set (desc, field, GrB_COMP + GrB_STRUCTURE)) ; } else if (MATCH (s, "replace")) { - OK (GxB_Desc_set (D, field, GrB_REPLACE)) ; + OK (GxB_Desc_set (desc, field, GrB_REPLACE)) ; } else if (MATCH (s, "gustavson")) { - OK (GxB_Desc_set (D, field, GxB_AxB_GUSTAVSON)) ; + OK (GxB_Desc_set (desc, field, GxB_AxB_GUSTAVSON)) ; } else if (MATCH (s, "dot")) { - OK (GxB_Desc_set (D, field, GxB_AxB_DOT)) ; + OK (GxB_Desc_set (desc, field, GxB_AxB_DOT)) ; } else if (MATCH (s, "saxpy")) { - OK (GxB_Desc_set (D, field, GxB_AxB_SAXPY)) ; + OK (GxB_Desc_set (desc, field, GxB_AxB_SAXPY)) ; } else if (MATCH (s, "heap")) { - OK (GxB_Desc_set (D, field, GxB_AxB_HEAP)) ; + OK (GxB_Desc_set (desc, field, GxB_AxB_HEAP)) ; } else if (MATCH (s, "hash")) { - OK (GxB_Desc_set (D, field, GxB_AxB_HASH)) ; + OK (GxB_Desc_set (desc, field, GxB_AxB_HASH)) ; } else { @@ -115,9 +115,9 @@ static void get_descriptor // gb_mxarray_to_descriptor //------------------------------------------------------------------------------ -GrB_Descriptor gb_mxarray_to_descriptor // return a new descriptor +GrB_Descriptor gb_mxarray_to_descriptor // new descriptor, or NULL if none ( - const mxArray *D_matlab, // MATLAB struct + const mxArray *desc_matlab, // MATLAB struct with possible descriptor kind_enum_t *kind, // GrB, sparse, or full GxB_Format_Value *fmt, // by row or by col base_enum_t *base // 0-based int, 1-based int, or 1-based double @@ -125,37 +125,45 @@ GrB_Descriptor gb_mxarray_to_descriptor // return a new descriptor { //-------------------------------------------------------------------------- - // check inputs + // check inputs and find the descriptor //-------------------------------------------------------------------------- - // By default, all mexFunctions return a GraphBLAS struct, to be wrapped in - // a GrB object in GrB.m. + // set the defaults if no descriptor is present (*kind) = KIND_GRB ; + (*fmt) = GxB_NO_FORMAT ; + (*base) = BASE_DEFAULT ; - CHECK_ERROR (D_matlab == NULL || !mxIsStruct (D_matlab), - "descriptor must be a struct") ; + if (desc_matlab == NULL || !mxIsStruct (desc_matlab) + || mxGetField (desc_matlab, 0, "GraphBLAS") != NULL) + { + // If present, the descriptor is a struct whose first field is not + // "desc.GraphBLAS" (since that is a GrB matrix struct, not a + // descriptor). If not present, the GraphBLAS descriptor is NULL. + // This is not an error. + return (NULL) ; + } //-------------------------------------------------------------------------- // create the GraphBLAS descriptor //-------------------------------------------------------------------------- - GrB_Descriptor D ; - OK (GrB_Descriptor_new (&D)) ; + GrB_Descriptor desc ; + OK (GrB_Descriptor_new (&desc)) ; // get each component of the descriptor struct - get_descriptor (D, D_matlab, "out" , GrB_OUTP) ; - get_descriptor (D, D_matlab, "in0" , GrB_INP0) ; - get_descriptor (D, D_matlab, "in1" , GrB_INP1) ; - get_descriptor (D, D_matlab, "mask" , GrB_MASK) ; - get_descriptor (D, D_matlab, "axb" , GxB_AxB_METHOD) ; - get_descriptor (D, D_matlab, "nthreads", GxB_NTHREADS) ; - get_descriptor (D, D_matlab, "chunk" , GxB_CHUNK) ; + get_descriptor (desc, desc_matlab, "out" , GrB_OUTP) ; + get_descriptor (desc, desc_matlab, "in0" , GrB_INP0) ; + get_descriptor (desc, desc_matlab, "in1" , GrB_INP1) ; + get_descriptor (desc, desc_matlab, "mask" , GrB_MASK) ; + get_descriptor (desc, desc_matlab, "axb" , GxB_AxB_METHOD) ; + get_descriptor (desc, desc_matlab, "nthreads", GxB_NTHREADS) ; + get_descriptor (desc, desc_matlab, "chunk" , GxB_CHUNK) ; //-------------------------------------------------------------------------- // get the desired kind of output //-------------------------------------------------------------------------- - mxArray *mxkind = mxGetField (D_matlab, 0, "kind") ; + mxArray *mxkind = mxGetField (desc_matlab, 0, "kind") ; if (mxkind != NULL) { // get the string from the MATLAB field @@ -183,8 +191,7 @@ GrB_Descriptor gb_mxarray_to_descriptor // return a new descriptor // get the desired format of output, if any //-------------------------------------------------------------------------- - (*fmt) = GxB_NO_FORMAT ; - mxArray *mxfmt = mxGetField (D_matlab, 0, "format") ; + mxArray *mxfmt = mxGetField (desc_matlab, 0, "format") ; if (mxfmt != NULL) { (*fmt) = gb_mxstring_to_format (mxfmt) ; @@ -198,8 +205,7 @@ GrB_Descriptor gb_mxarray_to_descriptor // return a new descriptor // get the desired base //-------------------------------------------------------------------------- - (*base) = BASE_DEFAULT ; - mxArray *mxbase = mxGetField (D_matlab, 0, "base") ; + mxArray *mxbase = mxGetField (desc_matlab, 0, "base") ; if (mxbase != NULL) { // get the string from the MATLAB field @@ -245,6 +251,6 @@ GrB_Descriptor gb_mxarray_to_descriptor // return a new descriptor // return the non-null Descriptor to the caller //-------------------------------------------------------------------------- - return (D) ; + return (desc) ; } diff --git a/GraphBLAS/@GrB/private/util/gb_mxarray_to_list.c b/GraphBLAS/@GrB/private/util/gb_mxarray_to_list.c index e13a2d2289..cd5ee50555 100644 --- a/GraphBLAS/@GrB/private/util/gb_mxarray_to_list.c +++ b/GraphBLAS/@GrB/private/util/gb_mxarray_to_list.c @@ -68,20 +68,20 @@ int64_t *gb_mxarray_to_list // return List of integers (*allocated) = true ; int64_t *List = mxMalloc ((*len) * sizeof (int64_t)) ; if (class == mxDOUBLE_CLASS) - { + { // input list is 1-based double double *List_double = mxGetDoubles (mxList) ; bool ok = GB_matlab_helper3 (List, List_double, (*len), List_max) ; CHECK_ERROR (!ok, "index must be integer") ; } else if (class == mxINT64_CLASS) - { + { // input list is 1-based int64 int64_t *List_int64 = (int64_t *) mxGetInt64s (mxList) ; GB_matlab_helper3i (List, List_int64, (*len), List_max) ; } else // if (class == mxUINT64_CLASS) - { + { // input list is 1-based uint64 int64_t *List_int64 = (int64_t *) mxGetUint64s (mxList) ; GB_matlab_helper3i (List, List_int64, (*len), List_max) ; @@ -91,6 +91,7 @@ int64_t *gb_mxarray_to_list // return List of integers else { ERROR ("integer array must be double, int64, or uint64") ; + return (NULL) ; } } diff --git a/GraphBLAS/@GrB/private/util/gb_mxarray_type.c b/GraphBLAS/@GrB/private/util/gb_mxarray_type.c index 6fce69dcc7..096bce2569 100644 --- a/GraphBLAS/@GrB/private/util/gb_mxarray_type.c +++ b/GraphBLAS/@GrB/private/util/gb_mxarray_type.c @@ -17,36 +17,35 @@ GrB_Type gb_mxarray_type // return the GrB_Type of a MATLAB matrix GrB_Type type ; - switch (mxGetClassID (X)) - { - case mxLOGICAL_CLASS : type = GrB_BOOL ; break ; - case mxINT8_CLASS : type = GrB_INT8 ; break ; - case mxINT16_CLASS : type = GrB_INT16 ; break ; - case mxINT32_CLASS : type = GrB_INT32 ; break ; - case mxINT64_CLASS : type = GrB_INT64 ; break ; - case mxUINT8_CLASS : type = GrB_UINT8 ; break ; - case mxUINT16_CLASS : type = GrB_UINT16 ; break ; - case mxUINT32_CLASS : type = GrB_UINT32 ; break ; - case mxUINT64_CLASS : type = GrB_UINT64 ; break ; - case mxSINGLE_CLASS : type = GrB_FP32 ; break ; - case mxDOUBLE_CLASS : type = GrB_FP64 ; break ; - - case mxVOID_CLASS : - case mxCHAR_CLASS : - case mxUNKNOWN_CLASS : - case mxCELL_CLASS : - case mxSTRUCT_CLASS : - case mxFUNCTION_CLASS : - default : ERROR ("invalid type") ; - } - if (mxIsComplex (X)) { - #ifdef GB_COMPLEX_TYPE - type = gb_complex_type ; - #else - ERROR ("complex not yet supported") ; - #endif + + switch (mxGetClassID (X)) + { + case mxSINGLE_CLASS : type = GxB_FC32 ; break ; + case mxDOUBLE_CLASS : type = GxB_FC64 ; break ; + default : ERROR ("invalid type") ; + } + + } + else + { + + switch (mxGetClassID (X)) + { + case mxLOGICAL_CLASS : type = GrB_BOOL ; break ; + case mxINT8_CLASS : type = GrB_INT8 ; break ; + case mxINT16_CLASS : type = GrB_INT16 ; break ; + case mxINT32_CLASS : type = GrB_INT32 ; break ; + case mxINT64_CLASS : type = GrB_INT64 ; break ; + case mxUINT8_CLASS : type = GrB_UINT8 ; break ; + case mxUINT16_CLASS : type = GrB_UINT16 ; break ; + case mxUINT32_CLASS : type = GrB_UINT32 ; break ; + case mxUINT64_CLASS : type = GrB_UINT64 ; break ; + case mxSINGLE_CLASS : type = GrB_FP32 ; break ; + case mxDOUBLE_CLASS : type = GrB_FP64 ; break ; + default : ERROR ("invalid type") ; + } } return (type) ; diff --git a/GraphBLAS/@GrB/private/util/gb_mxcell_to_index.c b/GraphBLAS/@GrB/private/util/gb_mxcell_to_index.c index 74b959b5fb..8ebd224fc9 100644 --- a/GraphBLAS/@GrB/private/util/gb_mxcell_to_index.c +++ b/GraphBLAS/@GrB/private/util/gb_mxcell_to_index.c @@ -11,9 +11,9 @@ // I is a cell array. I contains 0, 1, 2, or 3 items: // -// 0: { } This is the MATLAB ':', like C(:,J), refering to all m rows, +// 0: { } This is the MATLAB ':', like C(:,J), refering to all m rows, // if C is m-by-n. -// 1: { list } A 1D list of row indices, like C(I,J) in MATLAB. +// 1: { list } A 1D list of row indices, like C(I,J) in MATLAB. // 2: { start,fini } start and fini are scalars (either double, int64, // or uint64). This defines I = start:fini in MATLAB colon // notation. @@ -54,8 +54,8 @@ GrB_Index *gb_mxcell_to_index // return index list I for (int k = 0 ; k < len ; k++) { // convert I_cell {k} content to an integer list - Item [k] = gb_mxarray_to_list (mxGetCell (I_cell, k), base, - &Item_allocated [k], &Item_len [k], &Item_max [k]) ; + Item [k] = (GrB_Index *) gb_mxarray_to_list (mxGetCell (I_cell, k), + base, &Item_allocated [k], &Item_len [k], &Item_max [k]) ; } //-------------------------------------------------------------------------- diff --git a/GraphBLAS/@GrB/private/util/gb_mxclass_to_mxstring.c b/GraphBLAS/@GrB/private/util/gb_mxclass_to_mxstring.c new file mode 100644 index 0000000000..124ce32524 --- /dev/null +++ b/GraphBLAS/@GrB/private/util/gb_mxclass_to_mxstring.c @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// gb_mxclass_to_mxstring: type of a MATLAB matrix +//------------------------------------------------------------------------------ + +// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. +// http://suitesparse.com See GraphBLAS/Doc/License.txt for license. + +//------------------------------------------------------------------------------ + +#include "gb_matlab.h" + +mxArray *gb_mxclass_to_mxstring (mxClassID class, bool is_complex) +{ + switch (class) + { + // a MATLAB sparse or dense matrix, valid for G = GrB (X), or + // for inputs to any GrB.method. + case mxLOGICAL_CLASS : return (mxCreateString ("logical")) ; + case mxINT8_CLASS : return (mxCreateString ("int8")) ; + case mxINT16_CLASS : return (mxCreateString ("int16")) ; + case mxINT32_CLASS : return (mxCreateString ("int32")) ; + case mxINT64_CLASS : return (mxCreateString ("int64")) ; + case mxUINT8_CLASS : return (mxCreateString ("uint8")) ; + case mxUINT16_CLASS : return (mxCreateString ("uint16")) ; + case mxUINT32_CLASS : return (mxCreateString ("uint32")) ; + case mxUINT64_CLASS : return (mxCreateString ("uint64")) ; + + case mxSINGLE_CLASS : + if (is_complex) + { + return (mxCreateString ("single complex")) ; + } + else + { + return (mxCreateString ("single")) ; + } + break ; + + case mxDOUBLE_CLASS : + if (is_complex) + { + return (mxCreateString ("double complex")) ; + } + else + { + return (mxCreateString ("double")) ; + } + break ; + + // a MATLAB struct, cell, char, void, function, or unknown + case mxSTRUCT_CLASS : return (mxCreateString ("struct")) ; + case mxCELL_CLASS : return (mxCreateString ("cell")) ; + case mxCHAR_CLASS : return (mxCreateString ("char")) ; + case mxVOID_CLASS : return (mxCreateString ("void")) ; + case mxFUNCTION_CLASS : return (mxCreateString ("function_handle")) ; + case mxUNKNOWN_CLASS : + default : return (mxCreateString ("unknown")) ; + } +} + diff --git a/GraphBLAS/@GrB/private/util/gb_mxstring_to_binop.c b/GraphBLAS/@GrB/private/util/gb_mxstring_to_binop.c index 30dd70d204..4cf66608da 100644 --- a/GraphBLAS/@GrB/private/util/gb_mxstring_to_binop.c +++ b/GraphBLAS/@GrB/private/util/gb_mxstring_to_binop.c @@ -12,7 +12,8 @@ GrB_BinaryOp gb_mxstring_to_binop // return binary operator from a string ( const mxArray *mxstring, // MATLAB string - const GrB_Type default_type // default type if not in the string + const GrB_Type atype, // type of A + const GrB_Type btype // type of B ) { @@ -40,6 +41,6 @@ GrB_BinaryOp gb_mxstring_to_binop // return binary operator from a string // convert the string to a binary operator //-------------------------------------------------------------------------- - return (gb_string_to_binop (opstring, default_type)) ; + return (gb_string_to_binop (opstring, atype, btype)) ; } diff --git a/GraphBLAS/@GrB/private/util/gb_mxstring_to_monoid.c b/GraphBLAS/@GrB/private/util/gb_mxstring_to_monoid.c index b2ffa86596..13ac0e65c7 100644 --- a/GraphBLAS/@GrB/private/util/gb_mxstring_to_monoid.c +++ b/GraphBLAS/@GrB/private/util/gb_mxstring_to_monoid.c @@ -12,7 +12,7 @@ GrB_Monoid gb_mxstring_to_monoid // return monoid from a string ( const mxArray *mxstring, // MATLAB string - const GrB_Type default_type // default type if not in the string + const GrB_Type type // default type if not in the string ) { @@ -37,6 +37,6 @@ GrB_Monoid gb_mxstring_to_monoid // return monoid from a string // convert the string to a monoid //-------------------------------------------------------------------------- - return (gb_string_to_monoid (opstring, default_type)) ; + return (gb_string_to_monoid (opstring, type)) ; } diff --git a/GraphBLAS/@GrB/private/util/gb_mxstring_to_semiring.c b/GraphBLAS/@GrB/private/util/gb_mxstring_to_semiring.c index 778be54c97..b0b0aafd43 100644 --- a/GraphBLAS/@GrB/private/util/gb_mxstring_to_semiring.c +++ b/GraphBLAS/@GrB/private/util/gb_mxstring_to_semiring.c @@ -12,7 +12,8 @@ GrB_Semiring gb_mxstring_to_semiring // return semiring from a string ( const mxArray *mxstring, // MATLAB string - const GrB_Type default_type // default type if not in the string + const GrB_Type atype, // type of A + const GrB_Type btype // type of B ) { @@ -37,6 +38,6 @@ GrB_Semiring gb_mxstring_to_semiring // return semiring from a string // convert the string to a semiring //-------------------------------------------------------------------------- - return (gb_string_to_semiring (semiring_string, default_type)) ; + return (gb_string_to_semiring (semiring_string, atype, btype)) ; } diff --git a/GraphBLAS/@GrB/private/util/gb_mxstring_to_type.c b/GraphBLAS/@GrB/private/util/gb_mxstring_to_type.c index d6e7da5e7d..3d0c304633 100644 --- a/GraphBLAS/@GrB/private/util/gb_mxstring_to_type.c +++ b/GraphBLAS/@GrB/private/util/gb_mxstring_to_type.c @@ -13,7 +13,7 @@ GrB_Type gb_mxstring_to_type // return the GrB_Type from a MATLAB string ( const mxArray *mxstring ) -{ +{ #define LEN 256 char s [LEN+2] ; diff --git a/GraphBLAS/@GrB/private/util/gb_norm.c b/GraphBLAS/@GrB/private/util/gb_norm.c index b3077c7e39..ba493b2a93 100644 --- a/GraphBLAS/@GrB/private/util/gb_norm.c +++ b/GraphBLAS/@GrB/private/util/gb_norm.c @@ -30,31 +30,49 @@ double gb_norm // compute norm (A,kind) OK (GxB_Matrix_type (&atype, A)) ; GrB_UnaryOp absop ; - GrB_BinaryOp timesop ; GrB_Monoid sumop, maxop, minop ; GrB_Vector t = NULL ; GrB_Matrix X = NULL ; + bool is_complex = false ; if (atype == GrB_FP32) - { + { // if A is FP32, use the FP32 type and operators xtype = GrB_FP32 ; absop = GxB_ABS_FP32 ; - sumop = GxB_PLUS_FP32_MONOID ; - timesop = GrB_TIMES_FP32 ; - maxop = GxB_MAX_FP32_MONOID ; - minop = GxB_MIN_FP32_MONOID ; + sumop = GrB_PLUS_MONOID_FP32 ; + maxop = GrB_MAX_MONOID_FP32 ; + minop = GrB_MIN_MONOID_FP32 ; + } + else if (atype == GxB_FC32) + { + // if A is FC32, use the FP32/FC32 type and operators + is_complex = true ; + xtype = GrB_FP32 ; + absop = GxB_ABS_FC32 ; + sumop = GrB_PLUS_MONOID_FP32 ; + maxop = GrB_MAX_MONOID_FP32 ; + minop = GrB_MIN_MONOID_FP32 ; + } + else if (atype == GxB_FC64) + { + // if A is FC64, use the FP64/FC64 type and operators + is_complex = true ; + xtype = GrB_FP64 ; + absop = GxB_ABS_FC64 ; + sumop = GrB_PLUS_MONOID_FP64 ; + maxop = GrB_MAX_MONOID_FP64 ; + minop = GrB_MIN_MONOID_FP64 ; } else - { + { // otherwise, use FP64 type and operators; this will typecast the // input matrix to FP64 if A is not of that type. xtype = GrB_FP64 ; absop = GxB_ABS_FP64 ; - sumop = GxB_PLUS_FP64_MONOID ; - timesop = GrB_TIMES_FP64 ; - maxop = GxB_MAX_FP64_MONOID ; - minop = GxB_MIN_FP64_MONOID ; + sumop = GrB_PLUS_MONOID_FP64 ; + maxop = GrB_MAX_MONOID_FP64 ; + minop = GrB_MIN_MONOID_FP64 ; } OK (GrB_Matrix_new (&X, xtype, nrows, ncols)) ; @@ -75,18 +93,37 @@ double gb_norm // compute norm (A,kind) switch (norm_kind) { - case 0: // Frobenius norm - case 2: // 2-norm + case 0 : // Frobenius norm + case 2 : // 2-norm - // X = A .* A - OK (GrB_eWiseMult_Matrix_BinaryOp (X, NULL, NULL, timesop, - A, A, NULL)) ; + if (is_complex) + { + // X = abs (A) + OK (GrB_Matrix_apply (X, NULL, NULL, absop, A, NULL)) ; + // X = X.^2 + if (atype == GxB_FC32) + { + OK (GrB_Matrix_apply_BinaryOp2nd_FP32 (X, NULL, NULL, + GxB_POW_FP32, X, (float) 2.0, NULL)) ; + } + else + { + OK (GrB_Matrix_apply_BinaryOp2nd_FP64 (X, NULL, NULL, + GxB_POW_FP64, X, (double) 2.0, NULL)) ; + } + } + else + { + // X = A.^2 + OK (GrB_Matrix_apply_BinaryOp2nd_FP64 (X, NULL, NULL, + GxB_POW_FP64, A, (double) 2.0, NULL)) ; + } // s = sum (X) OK (GrB_Matrix_reduce_FP64 (&s, NULL, sumop, X, NULL)) ; s = sqrt (s) ; break ; - case 1: // 1-norm + case 1 : // 1-norm // X = abs (A) OK (GrB_Matrix_apply (X, NULL, NULL, absop, A, NULL)) ; @@ -94,7 +131,7 @@ double gb_norm // compute norm (A,kind) OK (GrB_Matrix_reduce_FP64 (&s, NULL, sumop, X, NULL)) ; break ; - case INT64_MAX: // inf-norm + case INT64_MAX : // inf-norm // X = abs (A) OK (GrB_Matrix_apply (X, NULL, NULL, absop, A, NULL)) ; @@ -102,10 +139,10 @@ double gb_norm // compute norm (A,kind) OK (GrB_Matrix_reduce_FP64 (&s, NULL, maxop, X, NULL)) ; break ; - case INT64_MIN: // (-inf)-norm + case INT64_MIN : // (-inf)-norm - if (!GB_is_dense (A)) - { + if (GB_is_dense (A)) + { // X = abs (A) OK (GrB_Matrix_apply (X, NULL, NULL, absop, A, NULL)) ; // s = min (X) @@ -130,12 +167,12 @@ double gb_norm // compute norm (A,kind) switch (norm_kind) { - case 2: // 2-norm + case 2 : // 2-norm ERROR ("2-norm not available for GrB matrices") ; break ; - case 1: // 1-norm: max sum of columns of abs (A) + case 1 : // 1-norm: max sum of columns of abs (A) // X = abs (A) OK (GrB_Matrix_apply (X, NULL, NULL, absop, A, NULL)) ; @@ -148,7 +185,7 @@ double gb_norm // compute norm (A,kind) OK (GrB_Vector_reduce_FP64 (&s, NULL, maxop, t, NULL)) ; break ; - case INT64_MAX: // inf-norm: max sum of rows of abs (A) + case INT64_MAX : // inf-norm: max sum of rows of abs (A) // X = abs (A) OK (GrB_Matrix_apply (X, NULL, NULL, absop, A, NULL)) ; @@ -160,12 +197,12 @@ double gb_norm // compute norm (A,kind) OK (GrB_Vector_reduce_FP64 (&s, NULL, maxop, t, NULL)) ; break ; - case INT64_MIN: + case INT64_MIN : ERROR ("(-inf)-norm not available for GrB matrices") ; break ; - default: + default : ERROR ("unknown norm") ; break ; diff --git a/GraphBLAS/@GrB/private/util/gb_norm_kind.c b/GraphBLAS/@GrB/private/util/gb_norm_kind.c index 90f0d37647..5c5e1853ee 100644 --- a/GraphBLAS/@GrB/private/util/gb_norm_kind.c +++ b/GraphBLAS/@GrB/private/util/gb_norm_kind.c @@ -22,39 +22,35 @@ int64_t gb_norm_kind (const mxArray *arg) char string [65] ; gb_mxstring_to_string (string, 64, arg, "kind") ; if (MATCH (string, "fro")) - { + { return (0) ; } else - { + { // unknown string ERROR ("unknown norm") ; } } - else if (mxIsScalar (arg)) + else { double x = mxGetScalar (arg) ; if (x == INFINITY) - { + { return (INT64_MAX) ; } else if (x == -INFINITY) - { + { return (INT64_MIN) ; } else if (x == 1 || x == 2) - { + { return ((int64_t) x) ; } else - { + { ERROR ("unknown norm") ; } } - else - { - // arg must be a scalar - ERROR ("unknown norm") ; - } + return (0) ; } diff --git a/GraphBLAS/@GrB/private/util/gb_round_binop.c b/GraphBLAS/@GrB/private/util/gb_round_binop.c new file mode 100644 index 0000000000..45546c33bb --- /dev/null +++ b/GraphBLAS/@GrB/private/util/gb_round_binop.c @@ -0,0 +1,20 @@ +//------------------------------------------------------------------------------ +// gb_round_binop: get a rounding operator +//------------------------------------------------------------------------------ + +// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. +// http://suitesparse.com See GraphBLAS/Doc/License.txt for license. + +//------------------------------------------------------------------------------ + +#include "gb_matlab.h" + +GrB_BinaryOp gb_round_binop (GrB_Type type) +{ + if (type == GrB_FP32) return (GxB_ROUND_FP32) ; + if (type == GrB_FP64) return (GxB_ROUND_FP64) ; + if (type == GxB_FC32) return (GxB_ROUND_FC32) ; + if (type == GxB_FC64) return (GxB_ROUND_FC64) ; + return (NULL) ; +} + diff --git a/GraphBLAS/@GrB/private/util/gb_semiring.c b/GraphBLAS/@GrB/private/util/gb_semiring.c index efd942f137..18bf34e068 100644 --- a/GraphBLAS/@GrB/private/util/gb_semiring.c +++ b/GraphBLAS/@GrB/private/util/gb_semiring.c @@ -8,15 +8,16 @@ //------------------------------------------------------------------------------ #include "gb_matlab.h" +#include "GB_binop.h" //------------------------------------------------------------------------------ // built-in semirings //------------------------------------------------------------------------------ -// Using built-in types and operators, 1355 unique semirings can be built. This -// count excludes redundant Boolean operators (for example GxB_TIMES_BOOL and -// GxB_LAND_BOOL are different operators but they are redundant since they -// always return the same result): +// Using built-in types and operators, many unique semirings can be built. Not +// all possible semirings that can be constructed from built-in types and +// operators are pre-defined. Below is a list of the 1473 pre-defined +// semirings. // 1000 semirings with a multiply operator TxT -> T where T is non-Boolean, from // the complete cross product of: @@ -42,6 +43,19 @@ // 11 multiply operators: // FIRST, SECOND, PAIR, LOR, LAND, LXOR, EQ, GT, LT, GE, LE +// 54 complex semirings: TxT -> T where T is float complex or double complex: + +// 3 complex monoids: PLUS, TIMES, ANY +// 2 complex types +// 9 complex multiply operators: +// FIRST, SECOND, PAIR, PLUS, MINUS, TIMES, DIV, RDIV, RMINUS + +// 64 bitwise semirings: TxT -> T where T is an unsigned integer: + +// 4 bitwise monoids: BOR, BAND, BXOR, BXNOR +// 4 bitwise multiply operators: BOR, BAND, BXOR, BXNOR +// 4 unsigned integer types: UINT8, UINT16, UINT32, UINT64 + // In the names below, each semiring has a name of the form GxB_add_mult_T // where add is the additive monoid, mult is the multiply operator, and T is // the type. The type T is always the type of x and y for the z=mult(x,y) @@ -49,7 +63,8 @@ // always the same. This is the type T for the first set, and Boolean for // the second and third sets of semirings. -// FUTURE: add GB_COMPLEX_TYPE and its semirings +// All 124 predefined semirings in the v1.3 spec are used below, in place of +// the older, equivalent, GxB* named semirings. //------------------------------------------------------------------------------ @@ -90,24 +105,19 @@ GrB_Semiring gb_semiring // built-in semiring, or NULL if error CHECK_ERROR (mult_opcode >= GB_USER_opcode, "invalid semiring (multiply operator not built-in)") ; - // this condition is true for all built-in operators, but not required for - // user-defined operators. FUTURE: likely true for complex semirings too. - CHECK_ERROR (mult->xtype != mult->ytype, - "invalid semiring (x and y types differ)") ; - //-------------------------------------------------------------------------- // rename redundant Boolean multiply operators //-------------------------------------------------------------------------- - GB_Type_code xycode = mult->xtype->code ; - GB_Type_code zcode = mult->ztype->code ; + GB_Type_code xcode = mult->xtype->code ; + GB_Type_code zcode = mult->ztype->code ; - CHECK_ERROR (xycode >= GB_UDT_code, + CHECK_ERROR (xcode >= GB_UDT_code, "invalid semiring (x and y type not built-in)") ; - CHECK_ERROR (zcode >= GB_UDT_code, + CHECK_ERROR (zcode >= GB_UDT_code, "invalid semiring (z type not built-in)") ; - if (xycode == GB_BOOL_code) + if (xcode == GB_BOOL_code) { // z = mult(x,y) where both x and y are Boolean. // DIV becomes FIRST @@ -130,14 +140,235 @@ GrB_Semiring gb_semiring // built-in semiring, or NULL if error add_opcode = GB_boolean_rename (add_opcode) ; } - // built-in binary operators always have this property. - // ASSERT (zcode == GB_BOOL_code || zcode == xycode) ; - //-------------------------------------------------------------------------- // launch the switch factory //-------------------------------------------------------------------------- - if (zcode != GB_BOOL_code) + if (zcode == GB_FC32_code) + { + + //---------------------------------------------------------------------- + // 27 single complex semirings + //---------------------------------------------------------------------- + + switch (mult_opcode) + { + + case GB_FIRST_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_FIRST_FC32 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_FIRST_FC32) ; + case GB_ANY_opcode : return (GxB_ANY_FIRST_FC32 ) ; + default : ; + } + break ; + + case GB_SECOND_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_SECOND_FC32 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_SECOND_FC32) ; + case GB_ANY_opcode : return (GxB_ANY_SECOND_FC32 ) ; + default : ; + } + break ; + + case GB_PAIR_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_PAIR_FC32 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_PAIR_FC32) ; + case GB_ANY_opcode : return (GxB_ANY_PAIR_FC32 ) ; + default : ; + } + break ; + + case GB_PLUS_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_PLUS_FC32 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_PLUS_FC32) ; + case GB_ANY_opcode : return (GxB_ANY_PLUS_FC32 ) ; + default : ; + } + break ; + + case GB_MINUS_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_MINUS_FC32 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_MINUS_FC32) ; + case GB_ANY_opcode : return (GxB_ANY_MINUS_FC32 ) ; + default : ; + } + break ; + + case GB_TIMES_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_TIMES_FC32 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_TIMES_FC32) ; + case GB_ANY_opcode : return (GxB_ANY_TIMES_FC32 ) ; + default : ; + } + break ; + + case GB_DIV_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_DIV_FC32 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_DIV_FC32) ; + case GB_ANY_opcode : return (GxB_ANY_DIV_FC32 ) ; + default : ; + } + break ; + + case GB_RDIV_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_RDIV_FC32 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_RDIV_FC32) ; + case GB_ANY_opcode : return (GxB_ANY_RDIV_FC32 ) ; + default : ; + } + break ; + + case GB_RMINUS_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_RMINUS_FC32 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_RMINUS_FC32) ; + case GB_ANY_opcode : return (GxB_ANY_RMINUS_FC32 ) ; + default : ; + } + break ; + default : ; + } + + } + else if (zcode == GB_FC64_code) + { + + //---------------------------------------------------------------------- + // 27 double complex semirings + //---------------------------------------------------------------------- + + switch (mult_opcode) + { + + case GB_FIRST_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_FIRST_FC64 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_FIRST_FC64) ; + case GB_ANY_opcode : return (GxB_ANY_FIRST_FC64 ) ; + default : ; + } + break ; + + case GB_SECOND_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_SECOND_FC64 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_SECOND_FC64) ; + case GB_ANY_opcode : return (GxB_ANY_SECOND_FC64 ) ; + default : ; + } + break ; + + case GB_PAIR_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_PAIR_FC64 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_PAIR_FC64) ; + case GB_ANY_opcode : return (GxB_ANY_PAIR_FC64 ) ; + default : ; + } + break ; + + case GB_PLUS_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_PLUS_FC64 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_PLUS_FC64) ; + case GB_ANY_opcode : return (GxB_ANY_PLUS_FC64 ) ; + default : ; + } + break ; + + case GB_MINUS_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_MINUS_FC64 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_MINUS_FC64) ; + case GB_ANY_opcode : return (GxB_ANY_MINUS_FC64 ) ; + default : ; + } + break ; + + case GB_TIMES_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_TIMES_FC64 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_TIMES_FC64) ; + case GB_ANY_opcode : return (GxB_ANY_TIMES_FC64 ) ; + default : ; + } + break ; + + case GB_DIV_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_DIV_FC64 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_DIV_FC64) ; + case GB_ANY_opcode : return (GxB_ANY_DIV_FC64 ) ; + default : ; + } + break ; + + case GB_RDIV_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_RDIV_FC64 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_RDIV_FC64) ; + case GB_ANY_opcode : return (GxB_ANY_RDIV_FC64 ) ; + default : ; + } + break ; + + case GB_RMINUS_opcode : + + switch (add_opcode) + { + case GB_PLUS_opcode : return (GxB_PLUS_RMINUS_FC64 ) ; + case GB_TIMES_opcode : return (GxB_TIMES_RMINUS_FC64) ; + case GB_ANY_opcode : return (GxB_ANY_RMINUS_FC64 ) ; + default : ; + } + break ; + default : ; + } + + } + else if (zcode != GB_BOOL_code) { //---------------------------------------------------------------------- @@ -149,1970 +380,2225 @@ GrB_Semiring gb_semiring // built-in semiring, or NULL if error switch (mult_opcode) { - case GB_FIRST_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_FIRST_opcode : // with (5 monoids) x (10 nonboolean types) + + switch (add_opcode) + { + + case GB_MIN_opcode : + + switch (zcode) + { + case GB_INT8_code : return (GrB_MIN_FIRST_SEMIRING_INT8 ) ; + case GB_INT16_code : return (GrB_MIN_FIRST_SEMIRING_INT16 ) ; + case GB_INT32_code : return (GrB_MIN_FIRST_SEMIRING_INT32 ) ; + case GB_INT64_code : return (GrB_MIN_FIRST_SEMIRING_INT64 ) ; + case GB_UINT8_code : return (GrB_MIN_FIRST_SEMIRING_UINT8 ) ; + case GB_UINT16_code : return (GrB_MIN_FIRST_SEMIRING_UINT16) ; + case GB_UINT32_code : return (GrB_MIN_FIRST_SEMIRING_UINT32) ; + case GB_UINT64_code : return (GrB_MIN_FIRST_SEMIRING_UINT64) ; + case GB_FP32_code : return (GrB_MIN_FIRST_SEMIRING_FP32 ) ; + case GB_FP64_code : return (GrB_MIN_FIRST_SEMIRING_FP64 ) ; + default : ; + } + break ; + + case GB_MAX_opcode : + + switch (zcode) + { + case GB_INT8_code : return (GrB_MAX_FIRST_SEMIRING_INT8 ) ; + case GB_INT16_code : return (GrB_MAX_FIRST_SEMIRING_INT16 ) ; + case GB_INT32_code : return (GrB_MAX_FIRST_SEMIRING_INT32 ) ; + case GB_INT64_code : return (GrB_MAX_FIRST_SEMIRING_INT64 ) ; + case GB_UINT8_code : return (GrB_MAX_FIRST_SEMIRING_UINT8 ) ; + case GB_UINT16_code : return (GrB_MAX_FIRST_SEMIRING_UINT16) ; + case GB_UINT32_code : return (GrB_MAX_FIRST_SEMIRING_UINT32) ; + case GB_UINT64_code : return (GrB_MAX_FIRST_SEMIRING_UINT64) ; + case GB_FP32_code : return (GrB_MAX_FIRST_SEMIRING_FP32 ) ; + case GB_FP64_code : return (GrB_MAX_FIRST_SEMIRING_FP64 ) ; + default : ; + } + break ; + + case GB_PLUS_opcode : + + switch (zcode) + { + case GB_INT8_code : return (GxB_PLUS_FIRST_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_FIRST_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_FIRST_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_FIRST_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_FIRST_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_FIRST_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_FIRST_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_FIRST_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_FIRST_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_FIRST_FP64 ) ; + default : ; + } + break ; + + case GB_TIMES_opcode : + + switch (zcode) + { + case GB_INT8_code : return (GxB_TIMES_FIRST_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_FIRST_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_FIRST_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_FIRST_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_FIRST_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_FIRST_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_FIRST_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_FIRST_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_FIRST_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_FIRST_FP64 ) ; + default : ; + } + break ; + + case GB_ANY_opcode : + + switch (zcode) + { + case GB_INT8_code : return (GxB_ANY_FIRST_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_FIRST_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_FIRST_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_FIRST_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_FIRST_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_FIRST_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_FIRST_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_FIRST_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_FIRST_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_FIRST_FP64 ) ; + default : ; + } + break ; + + default : ; + } + break ; + + case GB_SECOND_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_FIRST_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_FIRST_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_FIRST_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_FIRST_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_FIRST_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_FIRST_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_FIRST_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_FIRST_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_FIRST_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_FIRST_FP64 ) ; - default : ; + case GB_INT8_code : return (GrB_MIN_SECOND_SEMIRING_INT8 ) ; + case GB_INT16_code : return (GrB_MIN_SECOND_SEMIRING_INT16 ) ; + case GB_INT32_code : return (GrB_MIN_SECOND_SEMIRING_INT32 ) ; + case GB_INT64_code : return (GrB_MIN_SECOND_SEMIRING_INT64 ) ; + case GB_UINT8_code : return (GrB_MIN_SECOND_SEMIRING_UINT8 ) ; + case GB_UINT16_code : return (GrB_MIN_SECOND_SEMIRING_UINT16) ; + case GB_UINT32_code : return (GrB_MIN_SECOND_SEMIRING_UINT32) ; + case GB_UINT64_code : return (GrB_MIN_SECOND_SEMIRING_UINT64) ; + case GB_FP32_code : return (GrB_MIN_SECOND_SEMIRING_FP32 ) ; + case GB_FP64_code : return (GrB_MIN_SECOND_SEMIRING_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_FIRST_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_FIRST_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_FIRST_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_FIRST_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_FIRST_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_FIRST_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_FIRST_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_FIRST_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_FIRST_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_FIRST_FP64 ) ; - default : ; + case GB_INT8_code : return (GrB_MAX_SECOND_SEMIRING_INT8 ) ; + case GB_INT16_code : return (GrB_MAX_SECOND_SEMIRING_INT16 ) ; + case GB_INT32_code : return (GrB_MAX_SECOND_SEMIRING_INT32 ) ; + case GB_INT64_code : return (GrB_MAX_SECOND_SEMIRING_INT64 ) ; + case GB_UINT8_code : return (GrB_MAX_SECOND_SEMIRING_UINT8 ) ; + case GB_UINT16_code : return (GrB_MAX_SECOND_SEMIRING_UINT16) ; + case GB_UINT32_code : return (GrB_MAX_SECOND_SEMIRING_UINT32) ; + case GB_UINT64_code : return (GrB_MAX_SECOND_SEMIRING_UINT64) ; + case GB_FP32_code : return (GrB_MAX_SECOND_SEMIRING_FP32 ) ; + case GB_FP64_code : return (GrB_MAX_SECOND_SEMIRING_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_FIRST_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_FIRST_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_FIRST_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_FIRST_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_FIRST_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_FIRST_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_FIRST_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_FIRST_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_FIRST_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_FIRST_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_SECOND_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_SECOND_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_SECOND_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_SECOND_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_SECOND_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_SECOND_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_SECOND_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_SECOND_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_SECOND_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_SECOND_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_FIRST_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_FIRST_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_FIRST_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_FIRST_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_FIRST_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_FIRST_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_FIRST_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_FIRST_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_FIRST_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_FIRST_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_SECOND_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_SECOND_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_SECOND_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_SECOND_UINT16) ; + case GB_INT32_code : return (GxB_TIMES_SECOND_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_SECOND_UINT32) ; + case GB_INT64_code : return (GxB_TIMES_SECOND_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_SECOND_UINT64) ; + case GB_FP32_code : return (GxB_TIMES_SECOND_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_SECOND_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_FIRST_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_FIRST_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_FIRST_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_FIRST_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_FIRST_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_FIRST_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_FIRST_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_FIRST_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_FIRST_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_FIRST_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_SECOND_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_SECOND_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_SECOND_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_SECOND_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_SECOND_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_SECOND_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_SECOND_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_SECOND_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_SECOND_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_SECOND_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_SECOND_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_PAIR_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_SECOND_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_SECOND_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_SECOND_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_SECOND_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_SECOND_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_SECOND_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_SECOND_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_SECOND_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_SECOND_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_SECOND_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_PAIR_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_PAIR_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_PAIR_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_PAIR_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_PAIR_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_PAIR_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_PAIR_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_PAIR_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_PAIR_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_PAIR_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_SECOND_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_SECOND_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_SECOND_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_SECOND_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_SECOND_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_SECOND_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_SECOND_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_SECOND_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_SECOND_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_SECOND_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_PAIR_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_PAIR_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_PAIR_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_PAIR_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_PAIR_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_PAIR_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_PAIR_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_PAIR_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_PAIR_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_PAIR_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_SECOND_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_SECOND_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_SECOND_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_SECOND_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_SECOND_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_SECOND_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_SECOND_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_SECOND_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_SECOND_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_SECOND_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_PAIR_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_PAIR_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_PAIR_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_PAIR_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_PAIR_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_PAIR_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_PAIR_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_PAIR_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_PAIR_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_PAIR_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_SECOND_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_SECOND_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_SECOND_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_SECOND_UINT16) ; - case GB_INT32_code : return (GxB_TIMES_SECOND_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_SECOND_UINT32) ; - case GB_INT64_code : return (GxB_TIMES_SECOND_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_SECOND_UINT64) ; - case GB_FP32_code : return (GxB_TIMES_SECOND_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_SECOND_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_PAIR_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_PAIR_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_PAIR_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_PAIR_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_PAIR_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_PAIR_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_PAIR_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_PAIR_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_PAIR_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_PAIR_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_SECOND_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_SECOND_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_SECOND_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_SECOND_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_SECOND_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_SECOND_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_SECOND_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_SECOND_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_SECOND_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_SECOND_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_PAIR_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_PAIR_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_PAIR_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_PAIR_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_PAIR_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_PAIR_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_PAIR_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_PAIR_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_PAIR_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_PAIR_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_PAIR_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_MIN_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_PAIR_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_PAIR_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_PAIR_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_PAIR_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_PAIR_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_PAIR_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_PAIR_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_PAIR_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_PAIR_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_PAIR_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_MIN_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_MIN_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_MIN_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_MIN_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_MIN_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_MIN_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_MIN_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_MIN_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_MIN_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_MIN_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_PAIR_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_PAIR_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_PAIR_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_PAIR_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_PAIR_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_PAIR_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_PAIR_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_PAIR_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_PAIR_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_PAIR_FP64 ) ; - default : ; + case GB_INT8_code : return (GrB_MAX_MIN_SEMIRING_INT8 ) ; + case GB_INT16_code : return (GrB_MAX_MIN_SEMIRING_INT16 ) ; + case GB_INT32_code : return (GrB_MAX_MIN_SEMIRING_INT32 ) ; + case GB_INT64_code : return (GrB_MAX_MIN_SEMIRING_INT64 ) ; + case GB_UINT8_code : return (GrB_MAX_MIN_SEMIRING_UINT8 ) ; + case GB_UINT16_code : return (GrB_MAX_MIN_SEMIRING_UINT16) ; + case GB_UINT32_code : return (GrB_MAX_MIN_SEMIRING_UINT32) ; + case GB_UINT64_code : return (GrB_MAX_MIN_SEMIRING_UINT64) ; + case GB_FP32_code : return (GrB_MAX_MIN_SEMIRING_FP32 ) ; + case GB_FP64_code : return (GrB_MAX_MIN_SEMIRING_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_PAIR_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_PAIR_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_PAIR_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_PAIR_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_PAIR_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_PAIR_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_PAIR_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_PAIR_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_PAIR_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_PAIR_FP64 ) ; - default : ; + case GB_INT8_code : return (GrB_PLUS_MIN_SEMIRING_INT8 ) ; + case GB_INT16_code : return (GrB_PLUS_MIN_SEMIRING_INT16 ) ; + case GB_INT32_code : return (GrB_PLUS_MIN_SEMIRING_INT32 ) ; + case GB_INT64_code : return (GrB_PLUS_MIN_SEMIRING_INT64 ) ; + case GB_UINT8_code : return (GrB_PLUS_MIN_SEMIRING_UINT8 ) ; + case GB_UINT16_code : return (GrB_PLUS_MIN_SEMIRING_UINT16) ; + case GB_UINT32_code : return (GrB_PLUS_MIN_SEMIRING_UINT32) ; + case GB_UINT64_code : return (GrB_PLUS_MIN_SEMIRING_UINT64) ; + case GB_FP32_code : return (GrB_PLUS_MIN_SEMIRING_FP32 ) ; + case GB_FP64_code : return (GrB_PLUS_MIN_SEMIRING_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_PAIR_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_PAIR_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_PAIR_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_PAIR_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_PAIR_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_PAIR_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_PAIR_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_PAIR_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_PAIR_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_PAIR_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_MIN_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_MIN_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_MIN_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_MIN_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_MIN_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_MIN_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_MIN_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_MIN_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_MIN_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_MIN_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_PAIR_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_PAIR_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_PAIR_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_PAIR_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_PAIR_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_PAIR_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_PAIR_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_PAIR_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_PAIR_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_PAIR_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_MIN_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_MIN_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_MIN_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_MIN_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_MIN_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_MIN_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_MIN_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_MIN_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_MIN_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_MIN_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_MIN_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_MAX_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_MIN_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_MIN_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_MIN_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_MIN_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_MIN_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_MIN_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_MIN_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_MIN_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_MIN_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_MIN_FP64 ) ; - default : ; + case GB_INT8_code : return (GrB_MIN_MAX_SEMIRING_INT8 ) ; + case GB_INT16_code : return (GrB_MIN_MAX_SEMIRING_INT16 ) ; + case GB_INT32_code : return (GrB_MIN_MAX_SEMIRING_INT32 ) ; + case GB_INT64_code : return (GrB_MIN_MAX_SEMIRING_INT64 ) ; + case GB_UINT8_code : return (GrB_MIN_MAX_SEMIRING_UINT8 ) ; + case GB_UINT16_code : return (GrB_MIN_MAX_SEMIRING_UINT16) ; + case GB_UINT32_code : return (GrB_MIN_MAX_SEMIRING_UINT32) ; + case GB_UINT64_code : return (GrB_MIN_MAX_SEMIRING_UINT64) ; + case GB_FP32_code : return (GrB_MIN_MAX_SEMIRING_FP32 ) ; + case GB_FP64_code : return (GrB_MIN_MAX_SEMIRING_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_MIN_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_MIN_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_MIN_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_MIN_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_MIN_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_MIN_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_MIN_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_MIN_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_MIN_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_MIN_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_MAX_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_MAX_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_MAX_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_MAX_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_MAX_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_MAX_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_MAX_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_MAX_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_MAX_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_MAX_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_MIN_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_MIN_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_MIN_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_MIN_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_MIN_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_MIN_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_MIN_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_MIN_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_MIN_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_MIN_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_MAX_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_MAX_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_MAX_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_MAX_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_MAX_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_MAX_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_MAX_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_MAX_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_MAX_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_MAX_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_MIN_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_MIN_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_MIN_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_MIN_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_MIN_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_MIN_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_MIN_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_MIN_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_MIN_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_MIN_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_MAX_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_MAX_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_MAX_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_MAX_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_MAX_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_MAX_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_MAX_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_MAX_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_MAX_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_MAX_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_MIN_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_MIN_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_MIN_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_MIN_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_MIN_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_MIN_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_MIN_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_MIN_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_MIN_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_MIN_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_MAX_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_MAX_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_MAX_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_MAX_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_MAX_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_MAX_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_MAX_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_MAX_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_MAX_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_MAX_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_MAX_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_PLUS_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_MAX_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_MAX_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_MAX_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_MAX_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_MAX_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_MAX_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_MAX_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_MAX_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_MAX_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_MAX_FP64 ) ; - default : ; + case GB_INT8_code : return (GrB_MIN_PLUS_SEMIRING_INT8 ) ; + case GB_INT16_code : return (GrB_MIN_PLUS_SEMIRING_INT16 ) ; + case GB_INT32_code : return (GrB_MIN_PLUS_SEMIRING_INT32 ) ; + case GB_INT64_code : return (GrB_MIN_PLUS_SEMIRING_INT64 ) ; + case GB_UINT8_code : return (GrB_MIN_PLUS_SEMIRING_UINT8 ) ; + case GB_UINT16_code : return (GrB_MIN_PLUS_SEMIRING_UINT16) ; + case GB_UINT32_code : return (GrB_MIN_PLUS_SEMIRING_UINT32) ; + case GB_UINT64_code : return (GrB_MIN_PLUS_SEMIRING_UINT64) ; + case GB_FP32_code : return (GrB_MIN_PLUS_SEMIRING_FP32 ) ; + case GB_FP64_code : return (GrB_MIN_PLUS_SEMIRING_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_MAX_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_MAX_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_MAX_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_MAX_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_MAX_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_MAX_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_MAX_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_MAX_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_MAX_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_MAX_FP64 ) ; - default : ; + case GB_INT8_code : return (GrB_MAX_PLUS_SEMIRING_INT8 ) ; + case GB_INT16_code : return (GrB_MAX_PLUS_SEMIRING_INT16 ) ; + case GB_INT32_code : return (GrB_MAX_PLUS_SEMIRING_INT32 ) ; + case GB_INT64_code : return (GrB_MAX_PLUS_SEMIRING_INT64 ) ; + case GB_UINT8_code : return (GrB_MAX_PLUS_SEMIRING_UINT8 ) ; + case GB_UINT16_code : return (GrB_MAX_PLUS_SEMIRING_UINT16) ; + case GB_UINT32_code : return (GrB_MAX_PLUS_SEMIRING_UINT32) ; + case GB_UINT64_code : return (GrB_MAX_PLUS_SEMIRING_UINT64) ; + case GB_FP32_code : return (GrB_MAX_PLUS_SEMIRING_FP32 ) ; + case GB_FP64_code : return (GrB_MAX_PLUS_SEMIRING_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_MAX_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_MAX_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_MAX_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_MAX_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_MAX_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_MAX_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_MAX_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_MAX_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_MAX_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_MAX_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_PLUS_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_PLUS_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_PLUS_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_PLUS_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_PLUS_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_PLUS_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_PLUS_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_PLUS_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_PLUS_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_PLUS_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_MAX_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_MAX_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_MAX_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_MAX_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_MAX_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_MAX_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_MAX_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_MAX_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_MAX_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_MAX_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_PLUS_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_PLUS_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_PLUS_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_PLUS_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_PLUS_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_PLUS_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_PLUS_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_PLUS_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_PLUS_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_PLUS_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_MAX_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_MAX_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_MAX_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_MAX_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_MAX_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_MAX_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_MAX_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_MAX_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_MAX_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_MAX_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_PLUS_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_PLUS_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_PLUS_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_PLUS_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_PLUS_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_PLUS_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_PLUS_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_PLUS_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_PLUS_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_PLUS_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_PLUS_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_MINUS_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_PLUS_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_PLUS_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_PLUS_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_PLUS_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_PLUS_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_PLUS_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_PLUS_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_PLUS_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_PLUS_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_PLUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_MINUS_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_MINUS_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_MINUS_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_MINUS_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_MINUS_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_MINUS_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_MINUS_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_MINUS_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_MINUS_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_MINUS_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_PLUS_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_PLUS_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_PLUS_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_PLUS_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_PLUS_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_PLUS_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_PLUS_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_PLUS_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_PLUS_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_PLUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_MINUS_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_MINUS_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_MINUS_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_MINUS_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_MINUS_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_MINUS_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_MINUS_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_MINUS_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_MINUS_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_MINUS_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_PLUS_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_PLUS_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_PLUS_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_PLUS_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_PLUS_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_PLUS_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_PLUS_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_PLUS_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_PLUS_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_PLUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_MINUS_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_MINUS_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_MINUS_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_MINUS_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_MINUS_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_MINUS_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_MINUS_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_MINUS_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_MINUS_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_MINUS_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_PLUS_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_PLUS_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_PLUS_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_PLUS_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_PLUS_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_PLUS_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_PLUS_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_PLUS_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_PLUS_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_PLUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_MINUS_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_MINUS_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_MINUS_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_MINUS_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_MINUS_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_MINUS_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_MINUS_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_MINUS_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_MINUS_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_MINUS_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_PLUS_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_PLUS_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_PLUS_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_PLUS_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_PLUS_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_PLUS_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_PLUS_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_PLUS_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_PLUS_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_PLUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_MINUS_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_MINUS_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_MINUS_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_MINUS_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_MINUS_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_MINUS_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_MINUS_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_MINUS_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_MINUS_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_MINUS_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_MINUS_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_RMINUS_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_MINUS_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_MINUS_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_MINUS_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_MINUS_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_MINUS_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_MINUS_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_MINUS_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_MINUS_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_MINUS_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_MINUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_RMINUS_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_RMINUS_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_RMINUS_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_RMINUS_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_RMINUS_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_RMINUS_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_RMINUS_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_RMINUS_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_RMINUS_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_RMINUS_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_MINUS_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_MINUS_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_MINUS_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_MINUS_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_MINUS_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_MINUS_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_MINUS_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_MINUS_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_MINUS_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_MINUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_RMINUS_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_RMINUS_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_RMINUS_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_RMINUS_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_RMINUS_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_RMINUS_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_RMINUS_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_RMINUS_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_RMINUS_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_RMINUS_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_MINUS_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_MINUS_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_MINUS_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_MINUS_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_MINUS_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_MINUS_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_MINUS_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_MINUS_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_MINUS_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_MINUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_RMINUS_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_RMINUS_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_RMINUS_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_RMINUS_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_RMINUS_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_RMINUS_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_RMINUS_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_RMINUS_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_RMINUS_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_RMINUS_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_MINUS_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_MINUS_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_MINUS_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_MINUS_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_MINUS_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_MINUS_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_MINUS_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_MINUS_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_MINUS_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_MINUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_RMINUS_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_RMINUS_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_RMINUS_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_RMINUS_UINT16) ; + case GB_INT32_code : return (GxB_TIMES_RMINUS_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_RMINUS_UINT32) ; + case GB_INT64_code : return (GxB_TIMES_RMINUS_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_RMINUS_UINT64) ; + case GB_FP32_code : return (GxB_TIMES_RMINUS_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_RMINUS_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_MINUS_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_MINUS_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_MINUS_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_MINUS_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_MINUS_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_MINUS_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_MINUS_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_MINUS_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_MINUS_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_MINUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_RMINUS_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_RMINUS_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_RMINUS_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_RMINUS_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_RMINUS_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_RMINUS_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_RMINUS_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_RMINUS_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_RMINUS_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_RMINUS_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_RMINUS_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_TIMES_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_RMINUS_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_RMINUS_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_RMINUS_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_RMINUS_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_RMINUS_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_RMINUS_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_RMINUS_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_RMINUS_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_RMINUS_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_RMINUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GrB_MIN_TIMES_SEMIRING_INT8 ) ; + case GB_INT16_code : return (GrB_MIN_TIMES_SEMIRING_INT16 ) ; + case GB_INT32_code : return (GrB_MIN_TIMES_SEMIRING_INT32 ) ; + case GB_INT64_code : return (GrB_MIN_TIMES_SEMIRING_INT64 ) ; + case GB_UINT8_code : return (GrB_MIN_TIMES_SEMIRING_UINT8 ) ; + case GB_UINT16_code : return (GrB_MIN_TIMES_SEMIRING_UINT16) ; + case GB_UINT32_code : return (GrB_MIN_TIMES_SEMIRING_UINT32) ; + case GB_UINT64_code : return (GrB_MIN_TIMES_SEMIRING_UINT64) ; + case GB_FP32_code : return (GrB_MIN_TIMES_SEMIRING_FP32 ) ; + case GB_FP64_code : return (GrB_MIN_TIMES_SEMIRING_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_RMINUS_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_RMINUS_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_RMINUS_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_RMINUS_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_RMINUS_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_RMINUS_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_RMINUS_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_RMINUS_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_RMINUS_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_RMINUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GrB_MAX_TIMES_SEMIRING_INT8 ) ; + case GB_INT16_code : return (GrB_MAX_TIMES_SEMIRING_INT16 ) ; + case GB_INT32_code : return (GrB_MAX_TIMES_SEMIRING_INT32 ) ; + case GB_INT64_code : return (GrB_MAX_TIMES_SEMIRING_INT64 ) ; + case GB_UINT8_code : return (GrB_MAX_TIMES_SEMIRING_UINT8 ) ; + case GB_UINT16_code : return (GrB_MAX_TIMES_SEMIRING_UINT16) ; + case GB_UINT32_code : return (GrB_MAX_TIMES_SEMIRING_UINT32) ; + case GB_UINT64_code : return (GrB_MAX_TIMES_SEMIRING_UINT64) ; + case GB_FP32_code : return (GrB_MAX_TIMES_SEMIRING_FP32 ) ; + case GB_FP64_code : return (GrB_MAX_TIMES_SEMIRING_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_RMINUS_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_RMINUS_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_RMINUS_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_RMINUS_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_RMINUS_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_RMINUS_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_RMINUS_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_RMINUS_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_RMINUS_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_RMINUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GrB_PLUS_TIMES_SEMIRING_INT8 ) ; + case GB_INT16_code : return (GrB_PLUS_TIMES_SEMIRING_INT16 ) ; + case GB_INT32_code : return (GrB_PLUS_TIMES_SEMIRING_INT32 ) ; + case GB_INT64_code : return (GrB_PLUS_TIMES_SEMIRING_INT64 ) ; + case GB_UINT8_code : return (GrB_PLUS_TIMES_SEMIRING_UINT8 ) ; + case GB_UINT16_code : return (GrB_PLUS_TIMES_SEMIRING_UINT16) ; + case GB_UINT32_code : return (GrB_PLUS_TIMES_SEMIRING_UINT32) ; + case GB_UINT64_code : return (GrB_PLUS_TIMES_SEMIRING_UINT64) ; + case GB_FP32_code : return (GrB_PLUS_TIMES_SEMIRING_FP32 ) ; + case GB_FP64_code : return (GrB_PLUS_TIMES_SEMIRING_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_RMINUS_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_RMINUS_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_RMINUS_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_RMINUS_UINT16) ; - case GB_INT32_code : return (GxB_TIMES_RMINUS_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_RMINUS_UINT32) ; - case GB_INT64_code : return (GxB_TIMES_RMINUS_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_RMINUS_UINT64) ; - case GB_FP32_code : return (GxB_TIMES_RMINUS_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_RMINUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_TIMES_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_TIMES_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_TIMES_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_TIMES_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_TIMES_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_TIMES_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_TIMES_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_TIMES_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_TIMES_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_TIMES_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_RMINUS_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_RMINUS_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_RMINUS_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_RMINUS_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_RMINUS_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_RMINUS_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_RMINUS_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_RMINUS_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_RMINUS_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_RMINUS_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_TIMES_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_TIMES_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_TIMES_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_TIMES_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_TIMES_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_TIMES_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_TIMES_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_TIMES_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_TIMES_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_TIMES_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_TIMES_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_DIV_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_TIMES_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_TIMES_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_TIMES_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_TIMES_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_TIMES_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_TIMES_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_TIMES_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_TIMES_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_TIMES_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_TIMES_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_DIV_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_DIV_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_DIV_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_DIV_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_DIV_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_DIV_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_DIV_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_DIV_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_DIV_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_DIV_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_TIMES_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_TIMES_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_TIMES_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_TIMES_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_TIMES_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_TIMES_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_TIMES_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_TIMES_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_TIMES_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_TIMES_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_DIV_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_DIV_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_DIV_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_DIV_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_DIV_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_DIV_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_DIV_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_DIV_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_DIV_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_DIV_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_TIMES_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_TIMES_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_TIMES_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_TIMES_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_TIMES_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_TIMES_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_TIMES_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_TIMES_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_TIMES_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_TIMES_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_DIV_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_DIV_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_DIV_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_DIV_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_DIV_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_DIV_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_DIV_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_DIV_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_DIV_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_DIV_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_TIMES_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_TIMES_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_TIMES_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_TIMES_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_TIMES_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_TIMES_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_TIMES_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_TIMES_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_TIMES_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_TIMES_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_DIV_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_DIV_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_DIV_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_DIV_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_DIV_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_DIV_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_DIV_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_DIV_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_DIV_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_DIV_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_TIMES_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_TIMES_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_TIMES_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_TIMES_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_TIMES_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_TIMES_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_TIMES_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_TIMES_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_TIMES_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_TIMES_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_DIV_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_DIV_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_DIV_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_DIV_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_DIV_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_DIV_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_DIV_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_DIV_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_DIV_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_DIV_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_DIV_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_RDIV_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_DIV_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_DIV_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_DIV_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_DIV_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_DIV_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_DIV_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_DIV_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_DIV_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_DIV_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_DIV_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_RDIV_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_RDIV_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_RDIV_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_RDIV_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_RDIV_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_RDIV_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_RDIV_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_RDIV_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_RDIV_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_RDIV_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_DIV_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_DIV_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_DIV_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_DIV_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_DIV_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_DIV_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_DIV_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_DIV_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_DIV_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_DIV_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_RDIV_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_RDIV_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_RDIV_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_RDIV_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_RDIV_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_RDIV_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_RDIV_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_RDIV_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_RDIV_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_RDIV_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_DIV_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_DIV_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_DIV_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_DIV_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_DIV_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_DIV_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_DIV_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_DIV_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_DIV_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_DIV_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_RDIV_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_RDIV_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_RDIV_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_RDIV_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_RDIV_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_RDIV_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_RDIV_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_RDIV_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_RDIV_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_RDIV_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_DIV_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_DIV_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_DIV_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_DIV_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_DIV_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_DIV_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_DIV_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_DIV_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_DIV_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_DIV_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_RDIV_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_RDIV_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_RDIV_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_RDIV_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_RDIV_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_RDIV_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_RDIV_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_RDIV_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_RDIV_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_RDIV_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_DIV_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_DIV_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_DIV_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_DIV_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_DIV_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_DIV_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_DIV_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_DIV_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_DIV_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_DIV_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_RDIV_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_RDIV_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_RDIV_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_RDIV_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_RDIV_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_RDIV_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_RDIV_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_RDIV_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_RDIV_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_RDIV_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_RDIV_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_ISEQ_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_RDIV_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_RDIV_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_RDIV_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_RDIV_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_RDIV_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_RDIV_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_RDIV_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_RDIV_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_RDIV_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_RDIV_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_ISEQ_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_ISEQ_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_ISEQ_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_ISEQ_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_ISEQ_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_ISEQ_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_ISEQ_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_ISEQ_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_ISEQ_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_ISEQ_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_RDIV_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_RDIV_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_RDIV_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_RDIV_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_RDIV_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_RDIV_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_RDIV_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_RDIV_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_RDIV_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_RDIV_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_ISEQ_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_ISEQ_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_ISEQ_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_ISEQ_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_ISEQ_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_ISEQ_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_ISEQ_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_ISEQ_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_ISEQ_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_ISEQ_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_RDIV_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_RDIV_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_RDIV_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_RDIV_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_RDIV_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_RDIV_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_RDIV_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_RDIV_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_RDIV_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_RDIV_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_ISEQ_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_ISEQ_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_ISEQ_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_ISEQ_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_ISEQ_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_ISEQ_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_ISEQ_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_ISEQ_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_ISEQ_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_ISEQ_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_RDIV_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_RDIV_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_RDIV_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_RDIV_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_RDIV_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_RDIV_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_RDIV_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_RDIV_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_RDIV_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_RDIV_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_ISEQ_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_ISEQ_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_ISEQ_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_ISEQ_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_ISEQ_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_ISEQ_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_ISEQ_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_ISEQ_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_ISEQ_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_ISEQ_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_RDIV_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_RDIV_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_RDIV_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_RDIV_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_RDIV_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_RDIV_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_RDIV_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_RDIV_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_RDIV_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_RDIV_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_ISEQ_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_ISEQ_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_ISEQ_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_ISEQ_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_ISEQ_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_ISEQ_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_ISEQ_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_ISEQ_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_ISEQ_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_ISEQ_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_ISEQ_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_ISNE_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_ISEQ_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_ISEQ_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_ISEQ_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_ISEQ_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_ISEQ_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_ISEQ_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_ISEQ_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_ISEQ_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_ISEQ_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_ISEQ_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_ISNE_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_ISNE_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_ISNE_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_ISNE_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_ISNE_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_ISNE_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_ISNE_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_ISNE_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_ISNE_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_ISNE_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_ISEQ_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_ISEQ_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_ISEQ_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_ISEQ_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_ISEQ_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_ISEQ_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_ISEQ_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_ISEQ_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_ISEQ_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_ISEQ_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_ISNE_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_ISNE_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_ISNE_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_ISNE_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_ISNE_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_ISNE_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_ISNE_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_ISNE_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_ISNE_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_ISNE_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_ISEQ_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_ISEQ_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_ISEQ_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_ISEQ_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_ISEQ_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_ISEQ_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_ISEQ_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_ISEQ_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_ISEQ_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_ISEQ_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_ISNE_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_ISNE_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_ISNE_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_ISNE_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_ISNE_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_ISNE_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_ISNE_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_ISNE_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_ISNE_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_ISNE_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_ISEQ_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_ISEQ_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_ISEQ_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_ISEQ_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_ISEQ_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_ISEQ_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_ISEQ_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_ISEQ_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_ISEQ_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_ISEQ_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_ISNE_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_ISNE_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_ISNE_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_ISNE_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_ISNE_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_ISNE_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_ISNE_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_ISNE_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_ISNE_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_ISNE_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_ISEQ_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_ISEQ_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_ISEQ_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_ISEQ_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_ISEQ_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_ISEQ_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_ISEQ_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_ISEQ_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_ISEQ_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_ISEQ_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_ISNE_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_ISNE_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_ISNE_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_ISNE_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_ISNE_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_ISNE_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_ISNE_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_ISNE_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_ISNE_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_ISNE_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_ISNE_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_ISGT_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_ISNE_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_ISNE_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_ISNE_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_ISNE_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_ISNE_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_ISNE_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_ISNE_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_ISNE_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_ISNE_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_ISNE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_ISGT_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_ISGT_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_ISGT_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_ISGT_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_ISGT_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_ISGT_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_ISGT_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_ISGT_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_ISGT_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_ISGT_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_ISNE_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_ISNE_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_ISNE_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_ISNE_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_ISNE_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_ISNE_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_ISNE_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_ISNE_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_ISNE_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_ISNE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_ISGT_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_ISGT_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_ISGT_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_ISGT_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_ISGT_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_ISGT_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_ISGT_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_ISGT_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_ISGT_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_ISGT_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_ISNE_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_ISNE_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_ISNE_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_ISNE_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_ISNE_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_ISNE_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_ISNE_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_ISNE_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_ISNE_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_ISNE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_ISGT_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_ISGT_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_ISGT_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_ISGT_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_ISGT_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_ISGT_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_ISGT_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_ISGT_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_ISGT_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_ISGT_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_ISNE_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_ISNE_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_ISNE_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_ISNE_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_ISNE_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_ISNE_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_ISNE_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_ISNE_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_ISNE_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_ISNE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_ISGT_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_ISGT_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_ISGT_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_ISGT_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_ISGT_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_ISGT_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_ISGT_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_ISGT_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_ISGT_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_ISGT_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_ISNE_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_ISNE_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_ISNE_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_ISNE_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_ISNE_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_ISNE_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_ISNE_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_ISNE_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_ISNE_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_ISNE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_ISGT_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_ISGT_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_ISGT_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_ISGT_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_ISGT_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_ISGT_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_ISGT_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_ISGT_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_ISGT_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_ISGT_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_ISGT_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_ISLT_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_ISGT_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_ISGT_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_ISGT_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_ISGT_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_ISGT_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_ISGT_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_ISGT_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_ISGT_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_ISGT_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_ISGT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_ISLT_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_ISLT_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_ISLT_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_ISLT_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_ISLT_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_ISLT_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_ISLT_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_ISLT_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_ISLT_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_ISLT_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_ISGT_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_ISGT_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_ISGT_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_ISGT_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_ISGT_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_ISGT_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_ISGT_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_ISGT_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_ISGT_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_ISGT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_ISLT_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_ISLT_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_ISLT_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_ISLT_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_ISLT_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_ISLT_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_ISLT_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_ISLT_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_ISLT_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_ISLT_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_ISGT_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_ISGT_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_ISGT_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_ISGT_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_ISGT_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_ISGT_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_ISGT_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_ISGT_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_ISGT_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_ISGT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_ISLT_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_ISLT_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_ISLT_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_ISLT_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_ISLT_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_ISLT_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_ISLT_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_ISLT_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_ISLT_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_ISLT_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_ISGT_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_ISGT_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_ISGT_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_ISGT_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_ISGT_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_ISGT_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_ISGT_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_ISGT_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_ISGT_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_ISGT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_ISLT_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_ISLT_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_ISLT_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_ISLT_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_ISLT_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_ISLT_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_ISLT_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_ISLT_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_ISLT_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_ISLT_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_ISGT_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_ISGT_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_ISGT_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_ISGT_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_ISGT_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_ISGT_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_ISGT_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_ISGT_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_ISGT_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_ISGT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_ISLT_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_ISLT_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_ISLT_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_ISLT_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_ISLT_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_ISLT_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_ISLT_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_ISLT_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_ISLT_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_ISLT_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_ISLT_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_ISGE_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_ISLT_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_ISLT_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_ISLT_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_ISLT_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_ISLT_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_ISLT_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_ISLT_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_ISLT_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_ISLT_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_ISLT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_ISGE_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_ISGE_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_ISGE_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_ISGE_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_ISGE_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_ISGE_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_ISGE_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_ISGE_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_ISGE_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_ISGE_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_ISLT_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_ISLT_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_ISLT_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_ISLT_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_ISLT_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_ISLT_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_ISLT_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_ISLT_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_ISLT_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_ISLT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_ISGE_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_ISGE_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_ISGE_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_ISGE_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_ISGE_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_ISGE_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_ISGE_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_ISGE_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_ISGE_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_ISGE_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_ISLT_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_ISLT_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_ISLT_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_ISLT_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_ISLT_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_ISLT_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_ISLT_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_ISLT_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_ISLT_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_ISLT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_ISGE_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_ISGE_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_ISGE_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_ISGE_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_ISGE_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_ISGE_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_ISGE_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_ISGE_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_ISGE_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_ISGE_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_ISLT_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_ISLT_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_ISLT_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_ISLT_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_ISLT_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_ISLT_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_ISLT_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_ISLT_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_ISLT_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_ISLT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_ISGE_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_ISGE_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_ISGE_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_ISGE_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_ISGE_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_ISGE_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_ISGE_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_ISGE_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_ISGE_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_ISGE_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_ISLT_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_ISLT_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_ISLT_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_ISLT_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_ISLT_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_ISLT_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_ISLT_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_ISLT_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_ISLT_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_ISLT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_ISGE_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_ISGE_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_ISGE_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_ISGE_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_ISGE_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_ISGE_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_ISGE_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_ISGE_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_ISGE_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_ISGE_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_ISGE_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_ISLE_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_ISGE_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_ISGE_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_ISGE_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_ISGE_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_ISGE_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_ISGE_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_ISGE_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_ISGE_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_ISGE_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_ISGE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_ISLE_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_ISLE_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_ISLE_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_ISLE_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_ISLE_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_ISLE_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_ISLE_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_ISLE_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_ISLE_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_ISLE_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_ISGE_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_ISGE_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_ISGE_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_ISGE_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_ISGE_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_ISGE_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_ISGE_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_ISGE_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_ISGE_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_ISGE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_ISLE_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_ISLE_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_ISLE_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_ISLE_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_ISLE_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_ISLE_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_ISLE_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_ISLE_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_ISLE_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_ISLE_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_ISGE_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_ISGE_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_ISGE_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_ISGE_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_ISGE_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_ISGE_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_ISGE_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_ISGE_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_ISGE_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_ISGE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_ISLE_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_ISLE_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_ISLE_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_ISLE_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_ISLE_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_ISLE_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_ISLE_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_ISLE_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_ISLE_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_ISLE_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_ISGE_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_ISGE_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_ISGE_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_ISGE_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_ISGE_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_ISGE_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_ISGE_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_ISGE_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_ISGE_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_ISGE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_ISLE_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_ISLE_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_ISLE_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_ISLE_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_ISLE_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_ISLE_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_ISLE_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_ISLE_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_ISLE_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_ISLE_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_ISGE_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_ISGE_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_ISGE_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_ISGE_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_ISGE_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_ISGE_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_ISGE_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_ISGE_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_ISGE_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_ISGE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_ISLE_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_ISLE_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_ISLE_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_ISLE_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_ISLE_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_ISLE_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_ISLE_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_ISLE_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_ISLE_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_ISLE_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_ISLE_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_LOR_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_ISLE_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_ISLE_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_ISLE_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_ISLE_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_ISLE_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_ISLE_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_ISLE_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_ISLE_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_ISLE_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_ISLE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_LOR_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_LOR_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_LOR_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_LOR_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_LOR_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_LOR_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_LOR_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_LOR_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_LOR_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_LOR_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_ISLE_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_ISLE_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_ISLE_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_ISLE_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_ISLE_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_ISLE_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_ISLE_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_ISLE_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_ISLE_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_ISLE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_LOR_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_LOR_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_LOR_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_LOR_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_LOR_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_LOR_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_LOR_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_LOR_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_LOR_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_LOR_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_ISLE_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_ISLE_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_ISLE_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_ISLE_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_ISLE_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_ISLE_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_ISLE_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_ISLE_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_ISLE_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_ISLE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_LOR_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_LOR_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_LOR_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_LOR_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_LOR_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_LOR_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_LOR_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_LOR_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_LOR_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_LOR_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_ISLE_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_ISLE_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_ISLE_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_ISLE_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_ISLE_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_ISLE_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_ISLE_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_ISLE_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_ISLE_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_ISLE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_LOR_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_LOR_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_LOR_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_LOR_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_LOR_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_LOR_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_LOR_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_LOR_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_LOR_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_LOR_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_ISLE_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_ISLE_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_ISLE_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_ISLE_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_ISLE_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_ISLE_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_ISLE_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_ISLE_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_ISLE_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_ISLE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_LOR_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_LOR_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_LOR_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_LOR_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_LOR_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_LOR_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_LOR_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_LOR_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_LOR_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_LOR_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_LOR_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_LAND_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_LOR_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_LOR_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_LOR_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_LOR_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_LOR_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_LOR_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_LOR_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_LOR_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_LOR_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_LOR_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_LAND_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_LAND_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_LAND_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_LAND_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_LAND_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_LAND_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_LAND_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_LAND_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_LAND_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_LAND_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_LOR_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_LOR_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_LOR_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_LOR_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_LOR_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_LOR_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_LOR_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_LOR_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_LOR_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_LOR_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_LAND_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_LAND_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_LAND_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_LAND_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_LAND_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_LAND_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_LAND_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_LAND_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_LAND_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_LAND_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_LOR_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_LOR_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_LOR_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_LOR_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_LOR_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_LOR_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_LOR_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_LOR_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_LOR_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_LOR_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_LAND_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_LAND_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_LAND_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_LAND_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_LAND_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_LAND_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_LAND_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_LAND_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_LAND_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_LAND_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_LOR_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_LOR_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_LOR_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_LOR_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_LOR_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_LOR_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_LOR_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_LOR_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_LOR_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_LOR_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_LAND_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_LAND_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_LAND_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_LAND_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_LAND_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_LAND_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_LAND_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_LAND_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_LAND_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_LAND_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_LOR_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_LOR_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_LOR_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_LOR_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_LOR_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_LOR_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_LOR_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_LOR_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_LOR_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_LOR_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_LAND_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_LAND_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_LAND_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_LAND_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_LAND_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_LAND_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_LAND_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_LAND_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_LAND_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_LAND_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_LAND_opcode : // with (5 monoids) x (10 nonboolean types) + case GB_LXOR_opcode : // with (5 monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_MIN_opcode : + case GB_MIN_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_LAND_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_LAND_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_LAND_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_LAND_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_LAND_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_LAND_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_LAND_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_LAND_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_LAND_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_LAND_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MIN_LXOR_INT8 ) ; + case GB_UINT8_code : return (GxB_MIN_LXOR_UINT8 ) ; + case GB_INT16_code : return (GxB_MIN_LXOR_INT16 ) ; + case GB_UINT16_code : return (GxB_MIN_LXOR_UINT16 ) ; + case GB_INT32_code : return (GxB_MIN_LXOR_INT32 ) ; + case GB_UINT32_code : return (GxB_MIN_LXOR_UINT32 ) ; + case GB_INT64_code : return (GxB_MIN_LXOR_INT64 ) ; + case GB_UINT64_code : return (GxB_MIN_LXOR_UINT64 ) ; + case GB_FP32_code : return (GxB_MIN_LXOR_FP32 ) ; + case GB_FP64_code : return (GxB_MIN_LXOR_FP64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_MAX_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_LAND_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_LAND_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_LAND_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_LAND_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_LAND_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_LAND_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_LAND_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_LAND_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_LAND_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_LAND_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_MAX_LXOR_INT8 ) ; + case GB_UINT8_code : return (GxB_MAX_LXOR_UINT8 ) ; + case GB_INT16_code : return (GxB_MAX_LXOR_INT16 ) ; + case GB_UINT16_code : return (GxB_MAX_LXOR_UINT16 ) ; + case GB_INT32_code : return (GxB_MAX_LXOR_INT32 ) ; + case GB_UINT32_code : return (GxB_MAX_LXOR_UINT32 ) ; + case GB_INT64_code : return (GxB_MAX_LXOR_INT64 ) ; + case GB_UINT64_code : return (GxB_MAX_LXOR_UINT64 ) ; + case GB_FP32_code : return (GxB_MAX_LXOR_FP32 ) ; + case GB_FP64_code : return (GxB_MAX_LXOR_FP64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_PLUS_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_LAND_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_LAND_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_LAND_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_LAND_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_LAND_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_LAND_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_LAND_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_LAND_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_LAND_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_LAND_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_PLUS_LXOR_INT8 ) ; + case GB_UINT8_code : return (GxB_PLUS_LXOR_UINT8 ) ; + case GB_INT16_code : return (GxB_PLUS_LXOR_INT16 ) ; + case GB_UINT16_code : return (GxB_PLUS_LXOR_UINT16 ) ; + case GB_INT32_code : return (GxB_PLUS_LXOR_INT32 ) ; + case GB_UINT32_code : return (GxB_PLUS_LXOR_UINT32 ) ; + case GB_INT64_code : return (GxB_PLUS_LXOR_INT64 ) ; + case GB_UINT64_code : return (GxB_PLUS_LXOR_UINT64 ) ; + case GB_FP32_code : return (GxB_PLUS_LXOR_FP32 ) ; + case GB_FP64_code : return (GxB_PLUS_LXOR_FP64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_TIMES_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_LAND_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_LAND_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_LAND_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_LAND_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_LAND_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_LAND_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_LAND_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_LAND_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_LAND_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_LAND_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_TIMES_LXOR_INT8 ) ; + case GB_UINT8_code : return (GxB_TIMES_LXOR_UINT8 ) ; + case GB_INT16_code : return (GxB_TIMES_LXOR_INT16 ) ; + case GB_UINT16_code : return (GxB_TIMES_LXOR_UINT16 ) ; + case GB_INT32_code : return (GxB_TIMES_LXOR_INT32 ) ; + case GB_UINT32_code : return (GxB_TIMES_LXOR_UINT32 ) ; + case GB_INT64_code : return (GxB_TIMES_LXOR_INT64 ) ; + case GB_UINT64_code : return (GxB_TIMES_LXOR_UINT64 ) ; + case GB_FP32_code : return (GxB_TIMES_LXOR_FP32 ) ; + case GB_FP64_code : return (GxB_TIMES_LXOR_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_LAND_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_LAND_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_LAND_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_LAND_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_LAND_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_LAND_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_LAND_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_LAND_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_LAND_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_LAND_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_LXOR_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_LXOR_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_LXOR_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_LXOR_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_LXOR_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_LXOR_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_LXOR_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_LXOR_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_LXOR_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_LXOR_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_LXOR_opcode : // with (5 monoids) x (10 nonboolean types) + default : ; + } + + //---------------------------------------------------------------------- + // 64 bitwise semirings + //---------------------------------------------------------------------- + + switch (mult_opcode) + { + + case GB_BOR_opcode : switch (add_opcode) { + case GB_BOR_opcode : + + switch (zcode) + { + case GB_UINT8_code : return (GxB_BOR_BOR_UINT8 ) ; + case GB_UINT16_code : return (GxB_BOR_BOR_UINT16 ) ; + case GB_UINT32_code : return (GxB_BOR_BOR_UINT32 ) ; + case GB_UINT64_code : return (GxB_BOR_BOR_UINT64 ) ; + default : ; + } + break ; + + case GB_BAND_opcode : + + switch (zcode) + { + case GB_UINT8_code : return (GxB_BAND_BOR_UINT8 ) ; + case GB_UINT16_code : return (GxB_BAND_BOR_UINT16 ) ; + case GB_UINT32_code : return (GxB_BAND_BOR_UINT32 ) ; + case GB_UINT64_code : return (GxB_BAND_BOR_UINT64 ) ; + default : ; + } + break ; - case GB_MIN_opcode : + case GB_BXOR_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MIN_LXOR_INT8 ) ; - case GB_UINT8_code : return (GxB_MIN_LXOR_UINT8 ) ; - case GB_INT16_code : return (GxB_MIN_LXOR_INT16 ) ; - case GB_UINT16_code: return (GxB_MIN_LXOR_UINT16 ) ; - case GB_INT32_code : return (GxB_MIN_LXOR_INT32 ) ; - case GB_UINT32_code: return (GxB_MIN_LXOR_UINT32 ) ; - case GB_INT64_code : return (GxB_MIN_LXOR_INT64 ) ; - case GB_UINT64_code: return (GxB_MIN_LXOR_UINT64 ) ; - case GB_FP32_code : return (GxB_MIN_LXOR_FP32 ) ; - case GB_FP64_code : return (GxB_MIN_LXOR_FP64 ) ; - default : ; + case GB_UINT8_code : return (GxB_BXOR_BOR_UINT8 ) ; + case GB_UINT16_code : return (GxB_BXOR_BOR_UINT16 ) ; + case GB_UINT32_code : return (GxB_BXOR_BOR_UINT32 ) ; + case GB_UINT64_code : return (GxB_BXOR_BOR_UINT64 ) ; + default : ; } break ; - case GB_MAX_opcode : + case GB_BXNOR_opcode : + + switch (zcode) + { + case GB_UINT8_code : return (GxB_BXNOR_BOR_UINT8 ) ; + case GB_UINT16_code : return (GxB_BXNOR_BOR_UINT16 ) ; + case GB_UINT32_code : return (GxB_BXNOR_BOR_UINT32 ) ; + case GB_UINT64_code : return (GxB_BXNOR_BOR_UINT64 ) ; + default : ; + } + break ; + + default : ; + } + break ; + + case GB_BAND_opcode : + + switch (add_opcode) + { + case GB_BOR_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_MAX_LXOR_INT8 ) ; - case GB_UINT8_code : return (GxB_MAX_LXOR_UINT8 ) ; - case GB_INT16_code : return (GxB_MAX_LXOR_INT16 ) ; - case GB_UINT16_code: return (GxB_MAX_LXOR_UINT16 ) ; - case GB_INT32_code : return (GxB_MAX_LXOR_INT32 ) ; - case GB_UINT32_code: return (GxB_MAX_LXOR_UINT32 ) ; - case GB_INT64_code : return (GxB_MAX_LXOR_INT64 ) ; - case GB_UINT64_code: return (GxB_MAX_LXOR_UINT64 ) ; - case GB_FP32_code : return (GxB_MAX_LXOR_FP32 ) ; - case GB_FP64_code : return (GxB_MAX_LXOR_FP64 ) ; - default : ; + case GB_UINT8_code : return (GxB_BOR_BAND_UINT8 ) ; + case GB_UINT16_code : return (GxB_BOR_BAND_UINT16 ) ; + case GB_UINT32_code : return (GxB_BOR_BAND_UINT32 ) ; + case GB_UINT64_code : return (GxB_BOR_BAND_UINT64 ) ; + default : ; } break ; - case GB_PLUS_opcode : + case GB_BAND_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_PLUS_LXOR_INT8 ) ; - case GB_UINT8_code : return (GxB_PLUS_LXOR_UINT8 ) ; - case GB_INT16_code : return (GxB_PLUS_LXOR_INT16 ) ; - case GB_UINT16_code: return (GxB_PLUS_LXOR_UINT16 ) ; - case GB_INT32_code : return (GxB_PLUS_LXOR_INT32 ) ; - case GB_UINT32_code: return (GxB_PLUS_LXOR_UINT32 ) ; - case GB_INT64_code : return (GxB_PLUS_LXOR_INT64 ) ; - case GB_UINT64_code: return (GxB_PLUS_LXOR_UINT64 ) ; - case GB_FP32_code : return (GxB_PLUS_LXOR_FP32 ) ; - case GB_FP64_code : return (GxB_PLUS_LXOR_FP64 ) ; - default : ; + case GB_UINT8_code : return (GxB_BAND_BAND_UINT8 ) ; + case GB_UINT16_code : return (GxB_BAND_BAND_UINT16 ) ; + case GB_UINT32_code : return (GxB_BAND_BAND_UINT32 ) ; + case GB_UINT64_code : return (GxB_BAND_BAND_UINT64 ) ; + default : ; } break ; - case GB_TIMES_opcode : + case GB_BXOR_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_TIMES_LXOR_INT8 ) ; - case GB_UINT8_code : return (GxB_TIMES_LXOR_UINT8 ) ; - case GB_INT16_code : return (GxB_TIMES_LXOR_INT16 ) ; - case GB_UINT16_code: return (GxB_TIMES_LXOR_UINT16 ) ; - case GB_INT32_code : return (GxB_TIMES_LXOR_INT32 ) ; - case GB_UINT32_code: return (GxB_TIMES_LXOR_UINT32 ) ; - case GB_INT64_code : return (GxB_TIMES_LXOR_INT64 ) ; - case GB_UINT64_code: return (GxB_TIMES_LXOR_UINT64 ) ; - case GB_FP32_code : return (GxB_TIMES_LXOR_FP32 ) ; - case GB_FP64_code : return (GxB_TIMES_LXOR_FP64 ) ; - default : ; + case GB_UINT8_code : return (GxB_BXOR_BAND_UINT8 ) ; + case GB_UINT16_code : return (GxB_BXOR_BAND_UINT16 ) ; + case GB_UINT32_code : return (GxB_BXOR_BAND_UINT32 ) ; + case GB_UINT64_code : return (GxB_BXOR_BAND_UINT64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_BXNOR_opcode : switch (zcode) { - case GB_INT8_code : return (GxB_ANY_LXOR_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_LXOR_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_LXOR_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_LXOR_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_LXOR_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_LXOR_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_LXOR_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_LXOR_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_LXOR_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_LXOR_FP64 ) ; - default : ; + case GB_UINT8_code : return (GxB_BXNOR_BAND_UINT8 ) ; + case GB_UINT16_code : return (GxB_BXNOR_BAND_UINT16 ) ; + case GB_UINT32_code : return (GxB_BXNOR_BAND_UINT32 ) ; + case GB_UINT64_code : return (GxB_BXNOR_BAND_UINT64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - default : ; + case GB_BXOR_opcode : + + switch (add_opcode) + { + case GB_BOR_opcode : + + switch (zcode) + { + case GB_UINT8_code : return (GxB_BOR_BXOR_UINT8 ) ; + case GB_UINT16_code : return (GxB_BOR_BXOR_UINT16 ) ; + case GB_UINT32_code : return (GxB_BOR_BXOR_UINT32 ) ; + case GB_UINT64_code : return (GxB_BOR_BXOR_UINT64 ) ; + default : ; + } + break ; + + case GB_BAND_opcode : + + switch (zcode) + { + case GB_UINT8_code : return (GxB_BAND_BXOR_UINT8 ) ; + case GB_UINT16_code : return (GxB_BAND_BXOR_UINT16 ) ; + case GB_UINT32_code : return (GxB_BAND_BXOR_UINT32 ) ; + case GB_UINT64_code : return (GxB_BAND_BXOR_UINT64 ) ; + default : ; + } + break ; + + case GB_BXOR_opcode : + + switch (zcode) + { + case GB_UINT8_code : return (GxB_BXOR_BXOR_UINT8 ) ; + case GB_UINT16_code : return (GxB_BXOR_BXOR_UINT16 ) ; + case GB_UINT32_code : return (GxB_BXOR_BXOR_UINT32 ) ; + case GB_UINT64_code : return (GxB_BXOR_BXOR_UINT64 ) ; + default : ; + } + break ; + + case GB_BXNOR_opcode : + + switch (zcode) + { + case GB_UINT8_code : return (GxB_BXNOR_BXOR_UINT8 ) ; + case GB_UINT16_code : return (GxB_BXNOR_BXOR_UINT16 ) ; + case GB_UINT32_code : return (GxB_BXNOR_BXOR_UINT32 ) ; + case GB_UINT64_code : return (GxB_BXNOR_BXOR_UINT64 ) ; + default : ; + } + break ; + + default : ; + } + break ; + + case GB_BXNOR_opcode : + + switch (add_opcode) + { + case GB_BOR_opcode : + + switch (zcode) + { + case GB_UINT8_code : return (GxB_BOR_BXNOR_UINT8 ) ; + case GB_UINT16_code : return (GxB_BOR_BXNOR_UINT16 ) ; + case GB_UINT32_code : return (GxB_BOR_BXNOR_UINT32 ) ; + case GB_UINT64_code : return (GxB_BOR_BXNOR_UINT64 ) ; + default : ; + } + break ; + + case GB_BAND_opcode : + + switch (zcode) + { + case GB_UINT8_code : return (GxB_BAND_BXNOR_UINT8 ) ; + case GB_UINT16_code : return (GxB_BAND_BXNOR_UINT16 ) ; + case GB_UINT32_code : return (GxB_BAND_BXNOR_UINT32 ) ; + case GB_UINT64_code : return (GxB_BAND_BXNOR_UINT64 ) ; + default : ; + } + break ; + + case GB_BXOR_opcode : + + switch (zcode) + { + case GB_UINT8_code : return (GxB_BXOR_BXNOR_UINT8 ) ; + case GB_UINT16_code : return (GxB_BXOR_BXNOR_UINT16 ) ; + case GB_UINT32_code : return (GxB_BXOR_BXNOR_UINT32 ) ; + case GB_UINT64_code : return (GxB_BXOR_BXNOR_UINT64 ) ; + default : ; + } + break ; + + case GB_BXNOR_opcode : + + switch (zcode) + { + case GB_UINT8_code : return (GxB_BXNOR_BXNOR_UINT8 ) ; + case GB_UINT16_code : return (GxB_BXNOR_BXNOR_UINT16 ) ; + case GB_UINT32_code : return (GxB_BXNOR_BXNOR_UINT32 ) ; + case GB_UINT64_code : return (GxB_BXNOR_BXNOR_UINT64 ) ; + default : ; + } + break ; + + default : ; + } + break ; + + default : ; } + } - else if (xycode != GB_BOOL_code) + else if (xcode != GB_BOOL_code) { //---------------------------------------------------------------------- @@ -2124,596 +2610,603 @@ GrB_Semiring gb_semiring // built-in semiring, or NULL if error switch (mult_opcode) { - case GB_EQ_opcode : // with (5 bool monoids) x (10 nonboolean types) + case GB_EQ_opcode : // with (5 bool monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_LOR_opcode : + case GB_LOR_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LOR_EQ_INT8 ) ; - case GB_UINT8_code : return (GxB_LOR_EQ_UINT8 ) ; - case GB_INT16_code : return (GxB_LOR_EQ_INT16 ) ; - case GB_UINT16_code: return (GxB_LOR_EQ_UINT16 ) ; - case GB_INT32_code : return (GxB_LOR_EQ_INT32 ) ; - case GB_UINT32_code: return (GxB_LOR_EQ_UINT32 ) ; - case GB_INT64_code : return (GxB_LOR_EQ_INT64 ) ; - case GB_UINT64_code: return (GxB_LOR_EQ_UINT64 ) ; - case GB_FP32_code : return (GxB_LOR_EQ_FP32 ) ; - case GB_FP64_code : return (GxB_LOR_EQ_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LOR_EQ_INT8 ) ; + case GB_UINT8_code : return (GxB_LOR_EQ_UINT8 ) ; + case GB_INT16_code : return (GxB_LOR_EQ_INT16 ) ; + case GB_UINT16_code : return (GxB_LOR_EQ_UINT16 ) ; + case GB_INT32_code : return (GxB_LOR_EQ_INT32 ) ; + case GB_UINT32_code : return (GxB_LOR_EQ_UINT32 ) ; + case GB_INT64_code : return (GxB_LOR_EQ_INT64 ) ; + case GB_UINT64_code : return (GxB_LOR_EQ_UINT64 ) ; + case GB_FP32_code : return (GxB_LOR_EQ_FP32 ) ; + case GB_FP64_code : return (GxB_LOR_EQ_FP64 ) ; + default : ; } break ; - case GB_LAND_opcode : + case GB_LAND_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LAND_EQ_INT8 ) ; - case GB_UINT8_code : return (GxB_LAND_EQ_UINT8 ) ; - case GB_INT16_code : return (GxB_LAND_EQ_INT16 ) ; - case GB_UINT16_code: return (GxB_LAND_EQ_UINT16 ) ; - case GB_INT32_code : return (GxB_LAND_EQ_INT32 ) ; - case GB_UINT32_code: return (GxB_LAND_EQ_UINT32 ) ; - case GB_INT64_code : return (GxB_LAND_EQ_INT64 ) ; - case GB_UINT64_code: return (GxB_LAND_EQ_UINT64 ) ; - case GB_FP32_code : return (GxB_LAND_EQ_FP32 ) ; - case GB_FP64_code : return (GxB_LAND_EQ_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LAND_EQ_INT8 ) ; + case GB_UINT8_code : return (GxB_LAND_EQ_UINT8 ) ; + case GB_INT16_code : return (GxB_LAND_EQ_INT16 ) ; + case GB_UINT16_code : return (GxB_LAND_EQ_UINT16 ) ; + case GB_INT32_code : return (GxB_LAND_EQ_INT32 ) ; + case GB_UINT32_code : return (GxB_LAND_EQ_UINT32 ) ; + case GB_INT64_code : return (GxB_LAND_EQ_INT64 ) ; + case GB_UINT64_code : return (GxB_LAND_EQ_UINT64 ) ; + case GB_FP32_code : return (GxB_LAND_EQ_FP32 ) ; + case GB_FP64_code : return (GxB_LAND_EQ_FP64 ) ; + default : ; } break ; - case GB_LXOR_opcode : + case GB_LXOR_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LXOR_EQ_INT8 ) ; - case GB_UINT8_code : return (GxB_LXOR_EQ_UINT8 ) ; - case GB_INT16_code : return (GxB_LXOR_EQ_INT16 ) ; - case GB_UINT16_code: return (GxB_LXOR_EQ_UINT16 ) ; - case GB_INT32_code : return (GxB_LXOR_EQ_INT32 ) ; - case GB_UINT32_code: return (GxB_LXOR_EQ_UINT32 ) ; - case GB_INT64_code : return (GxB_LXOR_EQ_INT64 ) ; - case GB_UINT64_code: return (GxB_LXOR_EQ_UINT64 ) ; - case GB_FP32_code : return (GxB_LXOR_EQ_FP32 ) ; - case GB_FP64_code : return (GxB_LXOR_EQ_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LXOR_EQ_INT8 ) ; + case GB_UINT8_code : return (GxB_LXOR_EQ_UINT8 ) ; + case GB_INT16_code : return (GxB_LXOR_EQ_INT16 ) ; + case GB_UINT16_code : return (GxB_LXOR_EQ_UINT16 ) ; + case GB_INT32_code : return (GxB_LXOR_EQ_INT32 ) ; + case GB_UINT32_code : return (GxB_LXOR_EQ_UINT32 ) ; + case GB_INT64_code : return (GxB_LXOR_EQ_INT64 ) ; + case GB_UINT64_code : return (GxB_LXOR_EQ_UINT64 ) ; + case GB_FP32_code : return (GxB_LXOR_EQ_FP32 ) ; + case GB_FP64_code : return (GxB_LXOR_EQ_FP64 ) ; + default : ; } break ; - case GB_EQ_opcode : + case GB_EQ_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_EQ_EQ_INT8 ) ; - case GB_UINT8_code : return (GxB_EQ_EQ_UINT8 ) ; - case GB_INT16_code : return (GxB_EQ_EQ_INT16 ) ; - case GB_UINT16_code: return (GxB_EQ_EQ_UINT16 ) ; - case GB_INT32_code : return (GxB_EQ_EQ_INT32 ) ; - case GB_UINT32_code: return (GxB_EQ_EQ_UINT32 ) ; - case GB_INT64_code : return (GxB_EQ_EQ_INT64 ) ; - case GB_UINT64_code: return (GxB_EQ_EQ_UINT64 ) ; - case GB_FP32_code : return (GxB_EQ_EQ_FP32 ) ; - case GB_FP64_code : return (GxB_EQ_EQ_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_EQ_EQ_INT8 ) ; + case GB_UINT8_code : return (GxB_EQ_EQ_UINT8 ) ; + case GB_INT16_code : return (GxB_EQ_EQ_INT16 ) ; + case GB_UINT16_code : return (GxB_EQ_EQ_UINT16 ) ; + case GB_INT32_code : return (GxB_EQ_EQ_INT32 ) ; + case GB_UINT32_code : return (GxB_EQ_EQ_UINT32 ) ; + case GB_INT64_code : return (GxB_EQ_EQ_INT64 ) ; + case GB_UINT64_code : return (GxB_EQ_EQ_UINT64 ) ; + case GB_FP32_code : return (GxB_EQ_EQ_FP32 ) ; + case GB_FP64_code : return (GxB_EQ_EQ_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_ANY_EQ_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_EQ_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_EQ_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_EQ_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_EQ_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_EQ_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_EQ_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_EQ_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_EQ_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_EQ_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_EQ_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_EQ_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_EQ_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_EQ_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_EQ_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_EQ_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_EQ_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_EQ_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_EQ_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_EQ_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_NE_opcode : // with (5 bool monoids) x (10 nonboolean types) + case GB_NE_opcode : // with (5 bool monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_LOR_opcode : + case GB_LOR_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LOR_NE_INT8 ) ; - case GB_UINT8_code : return (GxB_LOR_NE_UINT8 ) ; - case GB_INT16_code : return (GxB_LOR_NE_INT16 ) ; - case GB_UINT16_code: return (GxB_LOR_NE_UINT16 ) ; - case GB_INT32_code : return (GxB_LOR_NE_INT32 ) ; - case GB_UINT32_code: return (GxB_LOR_NE_UINT32 ) ; - case GB_INT64_code : return (GxB_LOR_NE_INT64 ) ; - case GB_UINT64_code: return (GxB_LOR_NE_UINT64 ) ; - case GB_FP32_code : return (GxB_LOR_NE_FP32 ) ; - case GB_FP64_code : return (GxB_LOR_NE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LOR_NE_INT8 ) ; + case GB_UINT8_code : return (GxB_LOR_NE_UINT8 ) ; + case GB_INT16_code : return (GxB_LOR_NE_INT16 ) ; + case GB_UINT16_code : return (GxB_LOR_NE_UINT16 ) ; + case GB_INT32_code : return (GxB_LOR_NE_INT32 ) ; + case GB_UINT32_code : return (GxB_LOR_NE_UINT32 ) ; + case GB_INT64_code : return (GxB_LOR_NE_INT64 ) ; + case GB_UINT64_code : return (GxB_LOR_NE_UINT64 ) ; + case GB_FP32_code : return (GxB_LOR_NE_FP32 ) ; + case GB_FP64_code : return (GxB_LOR_NE_FP64 ) ; + default : ; } break ; - case GB_LAND_opcode : + case GB_LAND_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LAND_NE_INT8 ) ; - case GB_UINT8_code : return (GxB_LAND_NE_UINT8 ) ; - case GB_INT16_code : return (GxB_LAND_NE_INT16 ) ; - case GB_UINT16_code: return (GxB_LAND_NE_UINT16 ) ; - case GB_INT32_code : return (GxB_LAND_NE_INT32 ) ; - case GB_UINT32_code: return (GxB_LAND_NE_UINT32 ) ; - case GB_INT64_code : return (GxB_LAND_NE_INT64 ) ; - case GB_UINT64_code: return (GxB_LAND_NE_UINT64 ) ; - case GB_FP32_code : return (GxB_LAND_NE_FP32 ) ; - case GB_FP64_code : return (GxB_LAND_NE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LAND_NE_INT8 ) ; + case GB_UINT8_code : return (GxB_LAND_NE_UINT8 ) ; + case GB_INT16_code : return (GxB_LAND_NE_INT16 ) ; + case GB_UINT16_code : return (GxB_LAND_NE_UINT16 ) ; + case GB_INT32_code : return (GxB_LAND_NE_INT32 ) ; + case GB_UINT32_code : return (GxB_LAND_NE_UINT32 ) ; + case GB_INT64_code : return (GxB_LAND_NE_INT64 ) ; + case GB_UINT64_code : return (GxB_LAND_NE_UINT64 ) ; + case GB_FP32_code : return (GxB_LAND_NE_FP32 ) ; + case GB_FP64_code : return (GxB_LAND_NE_FP64 ) ; + default : ; } break ; - case GB_LXOR_opcode : + case GB_LXOR_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LXOR_NE_INT8 ) ; - case GB_UINT8_code : return (GxB_LXOR_NE_UINT8 ) ; - case GB_INT16_code : return (GxB_LXOR_NE_INT16 ) ; - case GB_UINT16_code: return (GxB_LXOR_NE_UINT16 ) ; - case GB_INT32_code : return (GxB_LXOR_NE_INT32 ) ; - case GB_UINT32_code: return (GxB_LXOR_NE_UINT32 ) ; - case GB_INT64_code : return (GxB_LXOR_NE_INT64 ) ; - case GB_UINT64_code: return (GxB_LXOR_NE_UINT64 ) ; - case GB_FP32_code : return (GxB_LXOR_NE_FP32 ) ; - case GB_FP64_code : return (GxB_LXOR_NE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LXOR_NE_INT8 ) ; + case GB_UINT8_code : return (GxB_LXOR_NE_UINT8 ) ; + case GB_INT16_code : return (GxB_LXOR_NE_INT16 ) ; + case GB_UINT16_code : return (GxB_LXOR_NE_UINT16 ) ; + case GB_INT32_code : return (GxB_LXOR_NE_INT32 ) ; + case GB_UINT32_code : return (GxB_LXOR_NE_UINT32 ) ; + case GB_INT64_code : return (GxB_LXOR_NE_INT64 ) ; + case GB_UINT64_code : return (GxB_LXOR_NE_UINT64 ) ; + case GB_FP32_code : return (GxB_LXOR_NE_FP32 ) ; + case GB_FP64_code : return (GxB_LXOR_NE_FP64 ) ; + default : ; } break ; - case GB_EQ_opcode : + case GB_EQ_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_EQ_NE_INT8 ) ; - case GB_UINT8_code : return (GxB_EQ_NE_UINT8 ) ; - case GB_INT16_code : return (GxB_EQ_NE_INT16 ) ; - case GB_UINT16_code: return (GxB_EQ_NE_UINT16 ) ; - case GB_INT32_code : return (GxB_EQ_NE_INT32 ) ; - case GB_UINT32_code: return (GxB_EQ_NE_UINT32 ) ; - case GB_INT64_code : return (GxB_EQ_NE_INT64 ) ; - case GB_UINT64_code: return (GxB_EQ_NE_UINT64 ) ; - case GB_FP32_code : return (GxB_EQ_NE_FP32 ) ; - case GB_FP64_code : return (GxB_EQ_NE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_EQ_NE_INT8 ) ; + case GB_UINT8_code : return (GxB_EQ_NE_UINT8 ) ; + case GB_INT16_code : return (GxB_EQ_NE_INT16 ) ; + case GB_UINT16_code : return (GxB_EQ_NE_UINT16 ) ; + case GB_INT32_code : return (GxB_EQ_NE_INT32 ) ; + case GB_UINT32_code : return (GxB_EQ_NE_UINT32 ) ; + case GB_INT64_code : return (GxB_EQ_NE_INT64 ) ; + case GB_UINT64_code : return (GxB_EQ_NE_UINT64 ) ; + case GB_FP32_code : return (GxB_EQ_NE_FP32 ) ; + case GB_FP64_code : return (GxB_EQ_NE_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_ANY_NE_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_NE_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_NE_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_NE_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_NE_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_NE_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_NE_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_NE_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_NE_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_NE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_NE_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_NE_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_NE_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_NE_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_NE_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_NE_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_NE_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_NE_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_NE_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_NE_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_GT_opcode : // with (5 bool monoids) x (10 nonboolean types) + case GB_GT_opcode : // with (5 bool monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_LOR_opcode : + case GB_LOR_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LOR_GT_INT8 ) ; - case GB_UINT8_code : return (GxB_LOR_GT_UINT8 ) ; - case GB_INT16_code : return (GxB_LOR_GT_INT16 ) ; - case GB_UINT16_code: return (GxB_LOR_GT_UINT16 ) ; - case GB_INT32_code : return (GxB_LOR_GT_INT32 ) ; - case GB_UINT32_code: return (GxB_LOR_GT_UINT32 ) ; - case GB_INT64_code : return (GxB_LOR_GT_INT64 ) ; - case GB_UINT64_code: return (GxB_LOR_GT_UINT64 ) ; - case GB_FP32_code : return (GxB_LOR_GT_FP32 ) ; - case GB_FP64_code : return (GxB_LOR_GT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LOR_GT_INT8 ) ; + case GB_UINT8_code : return (GxB_LOR_GT_UINT8 ) ; + case GB_INT16_code : return (GxB_LOR_GT_INT16 ) ; + case GB_UINT16_code : return (GxB_LOR_GT_UINT16 ) ; + case GB_INT32_code : return (GxB_LOR_GT_INT32 ) ; + case GB_UINT32_code : return (GxB_LOR_GT_UINT32 ) ; + case GB_INT64_code : return (GxB_LOR_GT_INT64 ) ; + case GB_UINT64_code : return (GxB_LOR_GT_UINT64 ) ; + case GB_FP32_code : return (GxB_LOR_GT_FP32 ) ; + case GB_FP64_code : return (GxB_LOR_GT_FP64 ) ; + default : ; } break ; - case GB_LAND_opcode : + case GB_LAND_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LAND_GT_INT8 ) ; - case GB_UINT8_code : return (GxB_LAND_GT_UINT8 ) ; - case GB_INT16_code : return (GxB_LAND_GT_INT16 ) ; - case GB_UINT16_code: return (GxB_LAND_GT_UINT16 ) ; - case GB_INT32_code : return (GxB_LAND_GT_INT32 ) ; - case GB_UINT32_code: return (GxB_LAND_GT_UINT32 ) ; - case GB_INT64_code : return (GxB_LAND_GT_INT64 ) ; - case GB_UINT64_code: return (GxB_LAND_GT_UINT64 ) ; - case GB_FP32_code : return (GxB_LAND_GT_FP32 ) ; - case GB_FP64_code : return (GxB_LAND_GT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LAND_GT_INT8 ) ; + case GB_UINT8_code : return (GxB_LAND_GT_UINT8 ) ; + case GB_INT16_code : return (GxB_LAND_GT_INT16 ) ; + case GB_UINT16_code : return (GxB_LAND_GT_UINT16 ) ; + case GB_INT32_code : return (GxB_LAND_GT_INT32 ) ; + case GB_UINT32_code : return (GxB_LAND_GT_UINT32 ) ; + case GB_INT64_code : return (GxB_LAND_GT_INT64 ) ; + case GB_UINT64_code : return (GxB_LAND_GT_UINT64 ) ; + case GB_FP32_code : return (GxB_LAND_GT_FP32 ) ; + case GB_FP64_code : return (GxB_LAND_GT_FP64 ) ; + default : ; } break ; - case GB_LXOR_opcode : + case GB_LXOR_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LXOR_GT_INT8 ) ; - case GB_UINT8_code : return (GxB_LXOR_GT_UINT8 ) ; - case GB_INT16_code : return (GxB_LXOR_GT_INT16 ) ; - case GB_UINT16_code: return (GxB_LXOR_GT_UINT16 ) ; - case GB_INT32_code : return (GxB_LXOR_GT_INT32 ) ; - case GB_UINT32_code: return (GxB_LXOR_GT_UINT32 ) ; - case GB_INT64_code : return (GxB_LXOR_GT_INT64 ) ; - case GB_UINT64_code: return (GxB_LXOR_GT_UINT64 ) ; - case GB_FP32_code : return (GxB_LXOR_GT_FP32 ) ; - case GB_FP64_code : return (GxB_LXOR_GT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LXOR_GT_INT8 ) ; + case GB_UINT8_code : return (GxB_LXOR_GT_UINT8 ) ; + case GB_INT16_code : return (GxB_LXOR_GT_INT16 ) ; + case GB_UINT16_code : return (GxB_LXOR_GT_UINT16 ) ; + case GB_INT32_code : return (GxB_LXOR_GT_INT32 ) ; + case GB_UINT32_code : return (GxB_LXOR_GT_UINT32 ) ; + case GB_INT64_code : return (GxB_LXOR_GT_INT64 ) ; + case GB_UINT64_code : return (GxB_LXOR_GT_UINT64 ) ; + case GB_FP32_code : return (GxB_LXOR_GT_FP32 ) ; + case GB_FP64_code : return (GxB_LXOR_GT_FP64 ) ; + default : ; } break ; - case GB_EQ_opcode : + case GB_EQ_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_EQ_GT_INT8 ) ; - case GB_UINT8_code : return (GxB_EQ_GT_UINT8 ) ; - case GB_INT16_code : return (GxB_EQ_GT_INT16 ) ; - case GB_UINT16_code: return (GxB_EQ_GT_UINT16 ) ; - case GB_INT32_code : return (GxB_EQ_GT_INT32 ) ; - case GB_UINT32_code: return (GxB_EQ_GT_UINT32 ) ; - case GB_INT64_code : return (GxB_EQ_GT_INT64 ) ; - case GB_UINT64_code: return (GxB_EQ_GT_UINT64 ) ; - case GB_FP32_code : return (GxB_EQ_GT_FP32 ) ; - case GB_FP64_code : return (GxB_EQ_GT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_EQ_GT_INT8 ) ; + case GB_UINT8_code : return (GxB_EQ_GT_UINT8 ) ; + case GB_INT16_code : return (GxB_EQ_GT_INT16 ) ; + case GB_UINT16_code : return (GxB_EQ_GT_UINT16 ) ; + case GB_INT32_code : return (GxB_EQ_GT_INT32 ) ; + case GB_UINT32_code : return (GxB_EQ_GT_UINT32 ) ; + case GB_INT64_code : return (GxB_EQ_GT_INT64 ) ; + case GB_UINT64_code : return (GxB_EQ_GT_UINT64 ) ; + case GB_FP32_code : return (GxB_EQ_GT_FP32 ) ; + case GB_FP64_code : return (GxB_EQ_GT_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_ANY_GT_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_GT_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_GT_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_GT_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_GT_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_GT_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_GT_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_GT_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_GT_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_GT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_GT_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_GT_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_GT_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_GT_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_GT_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_GT_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_GT_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_GT_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_GT_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_GT_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_LT_opcode : // with (5 bool monoids) x (10 nonboolean types) + case GB_LT_opcode : // with (5 bool monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_LOR_opcode : + case GB_LOR_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LOR_LT_INT8 ) ; - case GB_UINT8_code : return (GxB_LOR_LT_UINT8 ) ; - case GB_INT16_code : return (GxB_LOR_LT_INT16 ) ; - case GB_UINT16_code: return (GxB_LOR_LT_UINT16 ) ; - case GB_INT32_code : return (GxB_LOR_LT_INT32 ) ; - case GB_UINT32_code: return (GxB_LOR_LT_UINT32 ) ; - case GB_INT64_code : return (GxB_LOR_LT_INT64 ) ; - case GB_UINT64_code: return (GxB_LOR_LT_UINT64 ) ; - case GB_FP32_code : return (GxB_LOR_LT_FP32 ) ; - case GB_FP64_code : return (GxB_LOR_LT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LOR_LT_INT8 ) ; + case GB_UINT8_code : return (GxB_LOR_LT_UINT8 ) ; + case GB_INT16_code : return (GxB_LOR_LT_INT16 ) ; + case GB_UINT16_code : return (GxB_LOR_LT_UINT16 ) ; + case GB_INT32_code : return (GxB_LOR_LT_INT32 ) ; + case GB_UINT32_code : return (GxB_LOR_LT_UINT32 ) ; + case GB_INT64_code : return (GxB_LOR_LT_INT64 ) ; + case GB_UINT64_code : return (GxB_LOR_LT_UINT64 ) ; + case GB_FP32_code : return (GxB_LOR_LT_FP32 ) ; + case GB_FP64_code : return (GxB_LOR_LT_FP64 ) ; + default : ; } break ; - case GB_LAND_opcode : + case GB_LAND_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LAND_LT_INT8 ) ; - case GB_UINT8_code : return (GxB_LAND_LT_UINT8 ) ; - case GB_INT16_code : return (GxB_LAND_LT_INT16 ) ; - case GB_UINT16_code: return (GxB_LAND_LT_UINT16 ) ; - case GB_INT32_code : return (GxB_LAND_LT_INT32 ) ; - case GB_UINT32_code: return (GxB_LAND_LT_UINT32 ) ; - case GB_INT64_code : return (GxB_LAND_LT_INT64 ) ; - case GB_UINT64_code: return (GxB_LAND_LT_UINT64 ) ; - case GB_FP32_code : return (GxB_LAND_LT_FP32 ) ; - case GB_FP64_code : return (GxB_LAND_LT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LAND_LT_INT8 ) ; + case GB_UINT8_code : return (GxB_LAND_LT_UINT8 ) ; + case GB_INT16_code : return (GxB_LAND_LT_INT16 ) ; + case GB_UINT16_code : return (GxB_LAND_LT_UINT16 ) ; + case GB_INT32_code : return (GxB_LAND_LT_INT32 ) ; + case GB_UINT32_code : return (GxB_LAND_LT_UINT32 ) ; + case GB_INT64_code : return (GxB_LAND_LT_INT64 ) ; + case GB_UINT64_code : return (GxB_LAND_LT_UINT64 ) ; + case GB_FP32_code : return (GxB_LAND_LT_FP32 ) ; + case GB_FP64_code : return (GxB_LAND_LT_FP64 ) ; + default : ; } break ; - case GB_LXOR_opcode : + case GB_LXOR_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LXOR_LT_INT8 ) ; - case GB_UINT8_code : return (GxB_LXOR_LT_UINT8 ) ; - case GB_INT16_code : return (GxB_LXOR_LT_INT16 ) ; - case GB_UINT16_code: return (GxB_LXOR_LT_UINT16 ) ; - case GB_INT32_code : return (GxB_LXOR_LT_INT32 ) ; - case GB_UINT32_code: return (GxB_LXOR_LT_UINT32 ) ; - case GB_INT64_code : return (GxB_LXOR_LT_INT64 ) ; - case GB_UINT64_code: return (GxB_LXOR_LT_UINT64 ) ; - case GB_FP32_code : return (GxB_LXOR_LT_FP32 ) ; - case GB_FP64_code : return (GxB_LXOR_LT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LXOR_LT_INT8 ) ; + case GB_UINT8_code : return (GxB_LXOR_LT_UINT8 ) ; + case GB_INT16_code : return (GxB_LXOR_LT_INT16 ) ; + case GB_UINT16_code : return (GxB_LXOR_LT_UINT16 ) ; + case GB_INT32_code : return (GxB_LXOR_LT_INT32 ) ; + case GB_UINT32_code : return (GxB_LXOR_LT_UINT32 ) ; + case GB_INT64_code : return (GxB_LXOR_LT_INT64 ) ; + case GB_UINT64_code : return (GxB_LXOR_LT_UINT64 ) ; + case GB_FP32_code : return (GxB_LXOR_LT_FP32 ) ; + case GB_FP64_code : return (GxB_LXOR_LT_FP64 ) ; + default : ; } break ; - case GB_EQ_opcode : + case GB_EQ_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_EQ_LT_INT8 ) ; - case GB_UINT8_code : return (GxB_EQ_LT_UINT8 ) ; - case GB_INT16_code : return (GxB_EQ_LT_INT16 ) ; - case GB_UINT16_code: return (GxB_EQ_LT_UINT16 ) ; - case GB_INT32_code : return (GxB_EQ_LT_INT32 ) ; - case GB_UINT32_code: return (GxB_EQ_LT_UINT32 ) ; - case GB_INT64_code : return (GxB_EQ_LT_INT64 ) ; - case GB_UINT64_code: return (GxB_EQ_LT_UINT64 ) ; - case GB_FP32_code : return (GxB_EQ_LT_FP32 ) ; - case GB_FP64_code : return (GxB_EQ_LT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_EQ_LT_INT8 ) ; + case GB_UINT8_code : return (GxB_EQ_LT_UINT8 ) ; + case GB_INT16_code : return (GxB_EQ_LT_INT16 ) ; + case GB_UINT16_code : return (GxB_EQ_LT_UINT16 ) ; + case GB_INT32_code : return (GxB_EQ_LT_INT32 ) ; + case GB_UINT32_code : return (GxB_EQ_LT_UINT32 ) ; + case GB_INT64_code : return (GxB_EQ_LT_INT64 ) ; + case GB_UINT64_code : return (GxB_EQ_LT_UINT64 ) ; + case GB_FP32_code : return (GxB_EQ_LT_FP32 ) ; + case GB_FP64_code : return (GxB_EQ_LT_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_ANY_LT_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_LT_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_LT_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_LT_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_LT_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_LT_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_LT_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_LT_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_LT_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_LT_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_LT_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_LT_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_LT_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_LT_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_LT_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_LT_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_LT_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_LT_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_LT_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_LT_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_GE_opcode : // with (5 bool monoids) x (10 nonboolean types) + case GB_GE_opcode : // with (5 bool monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_LOR_opcode : + case GB_LOR_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LOR_GE_INT8 ) ; - case GB_UINT8_code : return (GxB_LOR_GE_UINT8 ) ; - case GB_INT16_code : return (GxB_LOR_GE_INT16 ) ; - case GB_UINT16_code: return (GxB_LOR_GE_UINT16 ) ; - case GB_INT32_code : return (GxB_LOR_GE_INT32 ) ; - case GB_UINT32_code: return (GxB_LOR_GE_UINT32 ) ; - case GB_INT64_code : return (GxB_LOR_GE_INT64 ) ; - case GB_UINT64_code: return (GxB_LOR_GE_UINT64 ) ; - case GB_FP32_code : return (GxB_LOR_GE_FP32 ) ; - case GB_FP64_code : return (GxB_LOR_GE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LOR_GE_INT8 ) ; + case GB_UINT8_code : return (GxB_LOR_GE_UINT8 ) ; + case GB_INT16_code : return (GxB_LOR_GE_INT16 ) ; + case GB_UINT16_code : return (GxB_LOR_GE_UINT16 ) ; + case GB_INT32_code : return (GxB_LOR_GE_INT32 ) ; + case GB_UINT32_code : return (GxB_LOR_GE_UINT32 ) ; + case GB_INT64_code : return (GxB_LOR_GE_INT64 ) ; + case GB_UINT64_code : return (GxB_LOR_GE_UINT64 ) ; + case GB_FP32_code : return (GxB_LOR_GE_FP32 ) ; + case GB_FP64_code : return (GxB_LOR_GE_FP64 ) ; + default : ; } break ; - case GB_LAND_opcode : + case GB_LAND_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LAND_GE_INT8 ) ; - case GB_UINT8_code : return (GxB_LAND_GE_UINT8 ) ; - case GB_INT16_code : return (GxB_LAND_GE_INT16 ) ; - case GB_UINT16_code: return (GxB_LAND_GE_UINT16 ) ; - case GB_INT32_code : return (GxB_LAND_GE_INT32 ) ; - case GB_UINT32_code: return (GxB_LAND_GE_UINT32 ) ; - case GB_INT64_code : return (GxB_LAND_GE_INT64 ) ; - case GB_UINT64_code: return (GxB_LAND_GE_UINT64 ) ; - case GB_FP32_code : return (GxB_LAND_GE_FP32 ) ; - case GB_FP64_code : return (GxB_LAND_GE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LAND_GE_INT8 ) ; + case GB_UINT8_code : return (GxB_LAND_GE_UINT8 ) ; + case GB_INT16_code : return (GxB_LAND_GE_INT16 ) ; + case GB_UINT16_code : return (GxB_LAND_GE_UINT16 ) ; + case GB_INT32_code : return (GxB_LAND_GE_INT32 ) ; + case GB_UINT32_code : return (GxB_LAND_GE_UINT32 ) ; + case GB_INT64_code : return (GxB_LAND_GE_INT64 ) ; + case GB_UINT64_code : return (GxB_LAND_GE_UINT64 ) ; + case GB_FP32_code : return (GxB_LAND_GE_FP32 ) ; + case GB_FP64_code : return (GxB_LAND_GE_FP64 ) ; + default : ; } break ; - case GB_LXOR_opcode : + case GB_LXOR_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LXOR_GE_INT8 ) ; - case GB_UINT8_code : return (GxB_LXOR_GE_UINT8 ) ; - case GB_INT16_code : return (GxB_LXOR_GE_INT16 ) ; - case GB_UINT16_code: return (GxB_LXOR_GE_UINT16 ) ; - case GB_INT32_code : return (GxB_LXOR_GE_INT32 ) ; - case GB_UINT32_code: return (GxB_LXOR_GE_UINT32 ) ; - case GB_INT64_code : return (GxB_LXOR_GE_INT64 ) ; - case GB_UINT64_code: return (GxB_LXOR_GE_UINT64 ) ; - case GB_FP32_code : return (GxB_LXOR_GE_FP32 ) ; - case GB_FP64_code : return (GxB_LXOR_GE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LXOR_GE_INT8 ) ; + case GB_UINT8_code : return (GxB_LXOR_GE_UINT8 ) ; + case GB_INT16_code : return (GxB_LXOR_GE_INT16 ) ; + case GB_UINT16_code : return (GxB_LXOR_GE_UINT16 ) ; + case GB_INT32_code : return (GxB_LXOR_GE_INT32 ) ; + case GB_UINT32_code : return (GxB_LXOR_GE_UINT32 ) ; + case GB_INT64_code : return (GxB_LXOR_GE_INT64 ) ; + case GB_UINT64_code : return (GxB_LXOR_GE_UINT64 ) ; + case GB_FP32_code : return (GxB_LXOR_GE_FP32 ) ; + case GB_FP64_code : return (GxB_LXOR_GE_FP64 ) ; + default : ; } break ; - case GB_EQ_opcode : + case GB_EQ_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_EQ_GE_INT8 ) ; - case GB_UINT8_code : return (GxB_EQ_GE_UINT8 ) ; - case GB_INT16_code : return (GxB_EQ_GE_INT16 ) ; - case GB_UINT16_code: return (GxB_EQ_GE_UINT16 ) ; - case GB_INT32_code : return (GxB_EQ_GE_INT32 ) ; - case GB_UINT32_code: return (GxB_EQ_GE_UINT32 ) ; - case GB_INT64_code : return (GxB_EQ_GE_INT64 ) ; - case GB_UINT64_code: return (GxB_EQ_GE_UINT64 ) ; - case GB_FP32_code : return (GxB_EQ_GE_FP32 ) ; - case GB_FP64_code : return (GxB_EQ_GE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_EQ_GE_INT8 ) ; + case GB_UINT8_code : return (GxB_EQ_GE_UINT8 ) ; + case GB_INT16_code : return (GxB_EQ_GE_INT16 ) ; + case GB_UINT16_code : return (GxB_EQ_GE_UINT16 ) ; + case GB_INT32_code : return (GxB_EQ_GE_INT32 ) ; + case GB_UINT32_code : return (GxB_EQ_GE_UINT32 ) ; + case GB_INT64_code : return (GxB_EQ_GE_INT64 ) ; + case GB_UINT64_code : return (GxB_EQ_GE_UINT64 ) ; + case GB_FP32_code : return (GxB_EQ_GE_FP32 ) ; + case GB_FP64_code : return (GxB_EQ_GE_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_ANY_GE_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_GE_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_GE_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_GE_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_GE_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_GE_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_GE_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_GE_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_GE_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_GE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_GE_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_GE_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_GE_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_GE_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_GE_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_GE_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_GE_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_GE_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_GE_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_GE_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - case GB_LE_opcode : // with (5 bool monoids) x (10 nonboolean types) + case GB_LE_opcode : // with (5 bool monoids) x (10 nonboolean types) switch (add_opcode) { - case GB_LOR_opcode : + case GB_LOR_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LOR_LE_INT8 ) ; - case GB_UINT8_code : return (GxB_LOR_LE_UINT8 ) ; - case GB_INT16_code : return (GxB_LOR_LE_INT16 ) ; - case GB_UINT16_code: return (GxB_LOR_LE_UINT16 ) ; - case GB_INT32_code : return (GxB_LOR_LE_INT32 ) ; - case GB_UINT32_code: return (GxB_LOR_LE_UINT32 ) ; - case GB_INT64_code : return (GxB_LOR_LE_INT64 ) ; - case GB_UINT64_code: return (GxB_LOR_LE_UINT64 ) ; - case GB_FP32_code : return (GxB_LOR_LE_FP32 ) ; - case GB_FP64_code : return (GxB_LOR_LE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LOR_LE_INT8 ) ; + case GB_UINT8_code : return (GxB_LOR_LE_UINT8 ) ; + case GB_INT16_code : return (GxB_LOR_LE_INT16 ) ; + case GB_UINT16_code : return (GxB_LOR_LE_UINT16 ) ; + case GB_INT32_code : return (GxB_LOR_LE_INT32 ) ; + case GB_UINT32_code : return (GxB_LOR_LE_UINT32 ) ; + case GB_INT64_code : return (GxB_LOR_LE_INT64 ) ; + case GB_UINT64_code : return (GxB_LOR_LE_UINT64 ) ; + case GB_FP32_code : return (GxB_LOR_LE_FP32 ) ; + case GB_FP64_code : return (GxB_LOR_LE_FP64 ) ; + default : ; } break ; - case GB_LAND_opcode : + case GB_LAND_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LAND_LE_INT8 ) ; - case GB_UINT8_code : return (GxB_LAND_LE_UINT8 ) ; - case GB_INT16_code : return (GxB_LAND_LE_INT16 ) ; - case GB_UINT16_code: return (GxB_LAND_LE_UINT16 ) ; - case GB_INT32_code : return (GxB_LAND_LE_INT32 ) ; - case GB_UINT32_code: return (GxB_LAND_LE_UINT32 ) ; - case GB_INT64_code : return (GxB_LAND_LE_INT64 ) ; - case GB_UINT64_code: return (GxB_LAND_LE_UINT64 ) ; - case GB_FP32_code : return (GxB_LAND_LE_FP32 ) ; - case GB_FP64_code : return (GxB_LAND_LE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LAND_LE_INT8 ) ; + case GB_UINT8_code : return (GxB_LAND_LE_UINT8 ) ; + case GB_INT16_code : return (GxB_LAND_LE_INT16 ) ; + case GB_UINT16_code : return (GxB_LAND_LE_UINT16 ) ; + case GB_INT32_code : return (GxB_LAND_LE_INT32 ) ; + case GB_UINT32_code : return (GxB_LAND_LE_UINT32 ) ; + case GB_INT64_code : return (GxB_LAND_LE_INT64 ) ; + case GB_UINT64_code : return (GxB_LAND_LE_UINT64 ) ; + case GB_FP32_code : return (GxB_LAND_LE_FP32 ) ; + case GB_FP64_code : return (GxB_LAND_LE_FP64 ) ; + default : ; } break ; - case GB_LXOR_opcode : + case GB_LXOR_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_LXOR_LE_INT8 ) ; - case GB_UINT8_code : return (GxB_LXOR_LE_UINT8 ) ; - case GB_INT16_code : return (GxB_LXOR_LE_INT16 ) ; - case GB_UINT16_code: return (GxB_LXOR_LE_UINT16 ) ; - case GB_INT32_code : return (GxB_LXOR_LE_INT32 ) ; - case GB_UINT32_code: return (GxB_LXOR_LE_UINT32 ) ; - case GB_INT64_code : return (GxB_LXOR_LE_INT64 ) ; - case GB_UINT64_code: return (GxB_LXOR_LE_UINT64 ) ; - case GB_FP32_code : return (GxB_LXOR_LE_FP32 ) ; - case GB_FP64_code : return (GxB_LXOR_LE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_LXOR_LE_INT8 ) ; + case GB_UINT8_code : return (GxB_LXOR_LE_UINT8 ) ; + case GB_INT16_code : return (GxB_LXOR_LE_INT16 ) ; + case GB_UINT16_code : return (GxB_LXOR_LE_UINT16 ) ; + case GB_INT32_code : return (GxB_LXOR_LE_INT32 ) ; + case GB_UINT32_code : return (GxB_LXOR_LE_UINT32 ) ; + case GB_INT64_code : return (GxB_LXOR_LE_INT64 ) ; + case GB_UINT64_code : return (GxB_LXOR_LE_UINT64 ) ; + case GB_FP32_code : return (GxB_LXOR_LE_FP32 ) ; + case GB_FP64_code : return (GxB_LXOR_LE_FP64 ) ; + default : ; } break ; - case GB_EQ_opcode : + case GB_EQ_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_EQ_LE_INT8 ) ; - case GB_UINT8_code : return (GxB_EQ_LE_UINT8 ) ; - case GB_INT16_code : return (GxB_EQ_LE_INT16 ) ; - case GB_UINT16_code: return (GxB_EQ_LE_UINT16 ) ; - case GB_INT32_code : return (GxB_EQ_LE_INT32 ) ; - case GB_UINT32_code: return (GxB_EQ_LE_UINT32 ) ; - case GB_INT64_code : return (GxB_EQ_LE_INT64 ) ; - case GB_UINT64_code: return (GxB_EQ_LE_UINT64 ) ; - case GB_FP32_code : return (GxB_EQ_LE_FP32 ) ; - case GB_FP64_code : return (GxB_EQ_LE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_EQ_LE_INT8 ) ; + case GB_UINT8_code : return (GxB_EQ_LE_UINT8 ) ; + case GB_INT16_code : return (GxB_EQ_LE_INT16 ) ; + case GB_UINT16_code : return (GxB_EQ_LE_UINT16 ) ; + case GB_INT32_code : return (GxB_EQ_LE_INT32 ) ; + case GB_UINT32_code : return (GxB_EQ_LE_UINT32 ) ; + case GB_INT64_code : return (GxB_EQ_LE_INT64 ) ; + case GB_UINT64_code : return (GxB_EQ_LE_UINT64 ) ; + case GB_FP32_code : return (GxB_EQ_LE_FP32 ) ; + case GB_FP64_code : return (GxB_EQ_LE_FP64 ) ; + default : ; } break ; - case GB_ANY_opcode : + case GB_ANY_opcode : - switch (xycode) + switch (xcode) { - case GB_INT8_code : return (GxB_ANY_LE_INT8 ) ; - case GB_UINT8_code : return (GxB_ANY_LE_UINT8 ) ; - case GB_INT16_code : return (GxB_ANY_LE_INT16 ) ; - case GB_UINT16_code: return (GxB_ANY_LE_UINT16 ) ; - case GB_INT32_code : return (GxB_ANY_LE_INT32 ) ; - case GB_UINT32_code: return (GxB_ANY_LE_UINT32 ) ; - case GB_INT64_code : return (GxB_ANY_LE_INT64 ) ; - case GB_UINT64_code: return (GxB_ANY_LE_UINT64 ) ; - case GB_FP32_code : return (GxB_ANY_LE_FP32 ) ; - case GB_FP64_code : return (GxB_ANY_LE_FP64 ) ; - default : ; + case GB_INT8_code : return (GxB_ANY_LE_INT8 ) ; + case GB_UINT8_code : return (GxB_ANY_LE_UINT8 ) ; + case GB_INT16_code : return (GxB_ANY_LE_INT16 ) ; + case GB_UINT16_code : return (GxB_ANY_LE_UINT16 ) ; + case GB_INT32_code : return (GxB_ANY_LE_INT32 ) ; + case GB_UINT32_code : return (GxB_ANY_LE_UINT32 ) ; + case GB_INT64_code : return (GxB_ANY_LE_INT64 ) ; + case GB_UINT64_code : return (GxB_ANY_LE_UINT64 ) ; + case GB_FP32_code : return (GxB_ANY_LE_FP32 ) ; + case GB_FP64_code : return (GxB_ANY_LE_FP64 ) ; + default : ; } break ; - default : ; + default : ; } + break ; - default : ; + default : ; } + } else { @@ -2727,144 +3220,155 @@ GrB_Semiring gb_semiring // built-in semiring, or NULL if error switch (mult_opcode) { - case GB_FIRST_opcode : + case GB_FIRST_opcode : switch (add_opcode) { - case GB_LOR_opcode : return (GxB_LOR_FIRST_BOOL ) ; - case GB_LAND_opcode : return (GxB_LAND_FIRST_BOOL ) ; - case GB_LXOR_opcode : return (GxB_LXOR_FIRST_BOOL ) ; - case GB_EQ_opcode : return (GxB_EQ_FIRST_BOOL ) ; - case GB_ANY_opcode : return (GxB_ANY_FIRST_BOOL ) ; - default : ; + case GB_LOR_opcode : return (GxB_LOR_FIRST_BOOL ) ; + case GB_LAND_opcode : return (GxB_LAND_FIRST_BOOL ) ; + case GB_LXOR_opcode : return (GxB_LXOR_FIRST_BOOL ) ; + case GB_EQ_opcode : return (GxB_EQ_FIRST_BOOL ) ; + case GB_ANY_opcode : return (GxB_ANY_FIRST_BOOL ) ; + default : ; } + break ; - case GB_SECOND_opcode : + case GB_SECOND_opcode : switch (add_opcode) { - case GB_LOR_opcode : return (GxB_LOR_SECOND_BOOL ) ; - case GB_LAND_opcode : return (GxB_LAND_SECOND_BOOL ) ; - case GB_LXOR_opcode : return (GxB_LXOR_SECOND_BOOL ) ; - case GB_EQ_opcode : return (GxB_EQ_SECOND_BOOL ) ; - case GB_ANY_opcode : return (GxB_ANY_SECOND_BOOL ) ; - default : ; + case GB_LOR_opcode : return (GxB_LOR_SECOND_BOOL ) ; + case GB_LAND_opcode : return (GxB_LAND_SECOND_BOOL) ; + case GB_LXOR_opcode : return (GxB_LXOR_SECOND_BOOL) ; + case GB_EQ_opcode : return (GxB_EQ_SECOND_BOOL ) ; + case GB_ANY_opcode : return (GxB_ANY_SECOND_BOOL ) ; + default : ; } + break ; - case GB_PAIR_opcode : + case GB_PAIR_opcode : switch (add_opcode) { - case GB_LOR_opcode : return (GxB_LOR_PAIR_BOOL ) ; - case GB_LAND_opcode : return (GxB_LAND_PAIR_BOOL ) ; - case GB_LXOR_opcode : return (GxB_LXOR_PAIR_BOOL ) ; - case GB_EQ_opcode : return (GxB_EQ_PAIR_BOOL ) ; - case GB_ANY_opcode : return (GxB_ANY_PAIR_BOOL ) ; - default : ; + case GB_LOR_opcode : return (GxB_LOR_PAIR_BOOL ) ; + case GB_LAND_opcode : return (GxB_LAND_PAIR_BOOL ) ; + case GB_LXOR_opcode : return (GxB_LXOR_PAIR_BOOL ) ; + case GB_EQ_opcode : return (GxB_EQ_PAIR_BOOL ) ; + case GB_ANY_opcode : return (GxB_ANY_PAIR_BOOL ) ; + default : ; } + break ; - case GB_LOR_opcode : + case GB_LOR_opcode : switch (add_opcode) { - case GB_LOR_opcode : return (GxB_LOR_LOR_BOOL ) ; - case GB_LAND_opcode : return (GxB_LAND_LOR_BOOL ) ; - case GB_LXOR_opcode : return (GxB_LXOR_LOR_BOOL ) ; - case GB_EQ_opcode : return (GxB_EQ_LOR_BOOL ) ; - case GB_ANY_opcode : return (GxB_ANY_LOR_BOOL ) ; - default : ; + case GB_LOR_opcode : return (GxB_LOR_LOR_BOOL ) ; + case GB_LAND_opcode : return (GrB_LAND_LOR_SEMIRING_BOOL ) ; + case GB_LXOR_opcode : return (GxB_LXOR_LOR_BOOL ) ; + case GB_EQ_opcode : return (GrB_LXNOR_LOR_SEMIRING_BOOL) ; + case GB_ANY_opcode : return (GxB_ANY_LOR_BOOL ) ; + default : ; } + break ; - case GB_LAND_opcode : + case GB_LAND_opcode : switch (add_opcode) { - case GB_LOR_opcode : return (GxB_LOR_LAND_BOOL ) ; - case GB_LAND_opcode : return (GxB_LAND_LAND_BOOL ) ; - case GB_LXOR_opcode : return (GxB_LXOR_LAND_BOOL ) ; - case GB_EQ_opcode : return (GxB_EQ_LAND_BOOL ) ; - case GB_ANY_opcode : return (GxB_ANY_LAND_BOOL ) ; - default : ; + case GB_LOR_opcode : return (GrB_LOR_LAND_SEMIRING_BOOL ) ; + case GB_LAND_opcode : return (GxB_LAND_LAND_BOOL ) ; + case GB_LXOR_opcode : return (GrB_LXOR_LAND_SEMIRING_BOOL) ; + case GB_EQ_opcode : return (GxB_EQ_LAND_BOOL ) ; + case GB_ANY_opcode : return (GxB_ANY_LAND_BOOL ) ; + default : ; } + break ; - case GB_LXOR_opcode : + case GB_LXOR_opcode : switch (add_opcode) { - case GB_LOR_opcode : return (GxB_LOR_LXOR_BOOL ) ; - case GB_LAND_opcode : return (GxB_LAND_LXOR_BOOL ) ; - case GB_LXOR_opcode : return (GxB_LXOR_LXOR_BOOL ) ; - case GB_EQ_opcode : return (GxB_EQ_LXOR_BOOL ) ; - case GB_ANY_opcode : return (GxB_ANY_LXOR_BOOL ) ; - default : ; + case GB_LOR_opcode : return (GxB_LOR_LXOR_BOOL ) ; + case GB_LAND_opcode : return (GxB_LAND_LXOR_BOOL ) ; + case GB_LXOR_opcode : return (GxB_LXOR_LXOR_BOOL ) ; + case GB_EQ_opcode : return (GxB_EQ_LXOR_BOOL ) ; + case GB_ANY_opcode : return (GxB_ANY_LXOR_BOOL ) ; + default : ; } + break ; - case GB_EQ_opcode : + case GB_EQ_opcode : switch (add_opcode) { - case GB_LOR_opcode : return (GxB_LOR_EQ_BOOL ) ; - case GB_LAND_opcode : return (GxB_LAND_EQ_BOOL ) ; - case GB_LXOR_opcode : return (GxB_LXOR_EQ_BOOL ) ; - case GB_EQ_opcode : return (GxB_EQ_EQ_BOOL ) ; - case GB_ANY_opcode : return (GxB_ANY_EQ_BOOL ) ; - default : ; + case GB_LOR_opcode : return (GxB_LOR_EQ_BOOL ) ; + case GB_LAND_opcode : return (GxB_LAND_EQ_BOOL) ; + case GB_LXOR_opcode : return (GxB_LXOR_EQ_BOOL) ; + case GB_EQ_opcode : return (GxB_EQ_EQ_BOOL ) ; + case GB_ANY_opcode : return (GxB_ANY_EQ_BOOL ) ; + default : ; } + break ; - case GB_GT_opcode : + case GB_GT_opcode : switch (add_opcode) { - case GB_LOR_opcode : return (GxB_LOR_GT_BOOL ) ; - case GB_LAND_opcode : return (GxB_LAND_GT_BOOL ) ; - case GB_LXOR_opcode : return (GxB_LXOR_GT_BOOL ) ; - case GB_EQ_opcode : return (GxB_EQ_GT_BOOL ) ; - case GB_ANY_opcode : return (GxB_ANY_GT_BOOL ) ; - default : ; + case GB_LOR_opcode : return (GxB_LOR_GT_BOOL ) ; + case GB_LAND_opcode : return (GxB_LAND_GT_BOOL) ; + case GB_LXOR_opcode : return (GxB_LXOR_GT_BOOL) ; + case GB_EQ_opcode : return (GxB_EQ_GT_BOOL ) ; + case GB_ANY_opcode : return (GxB_ANY_GT_BOOL ) ; + default : ; } + break ; - case GB_LT_opcode : + case GB_LT_opcode : switch (add_opcode) { - case GB_LOR_opcode : return (GxB_LOR_LT_BOOL ) ; - case GB_LAND_opcode : return (GxB_LAND_LT_BOOL ) ; - case GB_LXOR_opcode : return (GxB_LXOR_LT_BOOL ) ; - case GB_EQ_opcode : return (GxB_EQ_LT_BOOL ) ; - case GB_ANY_opcode : return (GxB_ANY_LT_BOOL ) ; - default : ; + case GB_LOR_opcode : return (GxB_LOR_LT_BOOL ) ; + case GB_LAND_opcode : return (GxB_LAND_LT_BOOL) ; + case GB_LXOR_opcode : return (GxB_LXOR_LT_BOOL) ; + case GB_EQ_opcode : return (GxB_EQ_LT_BOOL ) ; + case GB_ANY_opcode : return (GxB_ANY_LT_BOOL ) ; + default : ; } + break ; - case GB_GE_opcode : + case GB_GE_opcode : switch (add_opcode) { - case GB_LOR_opcode : return (GxB_LOR_GE_BOOL ) ; - case GB_LAND_opcode : return (GxB_LAND_GE_BOOL ) ; - case GB_LXOR_opcode : return (GxB_LXOR_GE_BOOL ) ; - case GB_EQ_opcode : return (GxB_EQ_GE_BOOL ) ; - case GB_ANY_opcode : return (GxB_ANY_GE_BOOL ) ; - default : ; + case GB_LOR_opcode : return (GxB_LOR_GE_BOOL ) ; + case GB_LAND_opcode : return (GxB_LAND_GE_BOOL) ; + case GB_LXOR_opcode : return (GxB_LXOR_GE_BOOL) ; + case GB_EQ_opcode : return (GxB_EQ_GE_BOOL ) ; + case GB_ANY_opcode : return (GxB_ANY_GE_BOOL ) ; + default : ; } + break ; - case GB_LE_opcode : + case GB_LE_opcode : switch (add_opcode) { - case GB_LOR_opcode : return (GxB_LOR_LE_BOOL ) ; - case GB_LAND_opcode : return (GxB_LAND_LE_BOOL ) ; - case GB_LXOR_opcode : return (GxB_LXOR_LE_BOOL ) ; - case GB_EQ_opcode : return (GxB_EQ_LE_BOOL ) ; - case GB_ANY_opcode : return (GxB_ANY_LE_BOOL ) ; - default : ; + case GB_LOR_opcode : return (GxB_LOR_LE_BOOL ) ; + case GB_LAND_opcode : return (GxB_LAND_LE_BOOL) ; + case GB_LXOR_opcode : return (GxB_LXOR_LE_BOOL) ; + case GB_EQ_opcode : return (GxB_EQ_LE_BOOL ) ; + case GB_ANY_opcode : return (GxB_ANY_LE_BOOL ) ; + default : ; } + break ; - default : ; + default : ; } } //-------------------------------------------------------------------------- - // not a built-in semiring; FUTURE: add complex semirings + // not a built-in semiring //-------------------------------------------------------------------------- ERROR ("invalid semiring (not found)") diff --git a/GraphBLAS/@GrB/private/util/gb_string_and_type_to_binop.c b/GraphBLAS/@GrB/private/util/gb_string_and_type_to_binop.c index 25156a971e..ff7b9c60bf 100644 --- a/GraphBLAS/@GrB/private/util/gb_string_and_type_to_binop.c +++ b/GraphBLAS/@GrB/private/util/gb_string_and_type_to_binop.c @@ -9,11 +9,15 @@ #include "gb_matlab.h" -// op_name: a MATLAB string defining the operator name (25 kinds): -// 11: 1st, 2nd, pair, min, max, +, -, rminus, *, /, \ -// 6: iseq, isne, isgt, islt, isge, isle, -// 6: ==, ~=, >, <, >=, <=, -// 3: ||, &&, xor +// op_name: a MATLAB string defining the operator name: +// 1st, 2nd, pair, min, max, +, -, rminus, *, /, \ +// iseq, isne, isgt, islt, isge, isle, +// ==, ~=, >, <, >=, <=, +// ||, &&, xor +// atan2, hypot, fmod, remainder, copysign, cmplx, pow, pow2 + +// bitwise operators: +// bitand, bitor, bitxor, bitxnor, bitget, bitset, bitclr, bitshift // The following synonyms are allowed for specifying these operators: // @@ -34,11 +38,7 @@ // || | or lor // && & and land // xor lxor - -// Total # of ops: 26*11 = 286, not including GrB_LOR, GrB_LAND, GrB_XOR, -// which are equivalent to the GxB_*_BOOL versions. - -// FUTURE: add complex operators +// pow2 ldexp GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type ( @@ -63,9 +63,8 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_FIRST_UINT64) ; if (type == GrB_FP32 ) return (GrB_FIRST_FP32 ) ; if (type == GrB_FP64 ) return (GrB_FIRST_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (... ) ; - #endif + if (type == GxB_FC32 ) return (GxB_FIRST_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_FIRST_FC64 ) ; } else if (MATCH (op_name, "2nd") || MATCH (op_name, "second")) @@ -82,28 +81,8 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_SECOND_UINT64) ; if (type == GrB_FP32 ) return (GrB_SECOND_FP32 ) ; if (type == GrB_FP64 ) return (GrB_SECOND_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif - - } - else if (MATCH (op_name, "pair")) - { - - if (type == GrB_BOOL ) return (GxB_PAIR_BOOL ) ; - if (type == GrB_INT8 ) return (GxB_PAIR_INT8 ) ; - if (type == GrB_INT16 ) return (GxB_PAIR_INT16 ) ; - if (type == GrB_INT32 ) return (GxB_PAIR_INT32 ) ; - if (type == GrB_INT64 ) return (GxB_PAIR_INT64 ) ; - if (type == GrB_UINT8 ) return (GxB_PAIR_UINT8 ) ; - if (type == GrB_UINT16) return (GxB_PAIR_UINT16) ; - if (type == GrB_UINT32) return (GxB_PAIR_UINT32) ; - if (type == GrB_UINT64) return (GxB_PAIR_UINT64) ; - if (type == GrB_FP32 ) return (GxB_PAIR_FP32 ) ; - if (type == GrB_FP64 ) return (GxB_PAIR_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (... ) ; - #endif + if (type == GxB_FC32 ) return (GxB_SECOND_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_SECOND_FC64 ) ; } else if (MATCH (op_name, "any")) @@ -120,9 +99,26 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GxB_ANY_UINT64) ; if (type == GrB_FP32 ) return (GxB_ANY_FP32 ) ; if (type == GrB_FP64 ) return (GxB_ANY_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (... ) ; - #endif + if (type == GxB_FC32 ) return (GxB_ANY_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_ANY_FC64 ) ; + + } + else if (MATCH (op_name, "pair")) + { + + if (type == GrB_BOOL ) return (GxB_PAIR_BOOL ) ; + if (type == GrB_INT8 ) return (GxB_PAIR_INT8 ) ; + if (type == GrB_INT16 ) return (GxB_PAIR_INT16 ) ; + if (type == GrB_INT32 ) return (GxB_PAIR_INT32 ) ; + if (type == GrB_INT64 ) return (GxB_PAIR_INT64 ) ; + if (type == GrB_UINT8 ) return (GxB_PAIR_UINT8 ) ; + if (type == GrB_UINT16) return (GxB_PAIR_UINT16) ; + if (type == GrB_UINT32) return (GxB_PAIR_UINT32) ; + if (type == GrB_UINT64) return (GxB_PAIR_UINT64) ; + if (type == GrB_FP32 ) return (GxB_PAIR_FP32 ) ; + if (type == GrB_FP64 ) return (GxB_PAIR_FP64 ) ; + if (type == GxB_FC32 ) return (GxB_PAIR_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_PAIR_FC64 ) ; } else if (MATCH (op_name, "min")) @@ -139,9 +135,7 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_MIN_UINT64) ; if (type == GrB_FP32 ) return (GrB_MIN_FP32 ) ; if (type == GrB_FP64 ) return (GrB_MIN_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + // no complex min } else if (MATCH (op_name, "max")) @@ -158,9 +152,7 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_MAX_UINT64) ; if (type == GrB_FP32 ) return (GrB_MAX_FP32 ) ; if (type == GrB_FP64 ) return (GrB_MAX_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + // no complex max } else if (MATCH (op_name, "+") || MATCH (op_name, "plus")) @@ -177,9 +169,8 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_PLUS_UINT64) ; if (type == GrB_FP32 ) return (GrB_PLUS_FP32 ) ; if (type == GrB_FP64 ) return (GrB_PLUS_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_PLUS_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_PLUS_FC64 ) ; } else if (MATCH (op_name, "-") || MATCH (op_name, "minus")) @@ -196,9 +187,8 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_MINUS_UINT64) ; if (type == GrB_FP32 ) return (GrB_MINUS_FP32 ) ; if (type == GrB_FP64 ) return (GrB_MINUS_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_MINUS_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_MINUS_FC64 ) ; } else if (MATCH (op_name, "rminus")) @@ -215,9 +205,8 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GxB_RMINUS_UINT64) ; if (type == GrB_FP32 ) return (GxB_RMINUS_FP32 ) ; if (type == GrB_FP64 ) return (GxB_RMINUS_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_RMINUS_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_RMINUS_FC64 ) ; } else if (MATCH (op_name, "*") || MATCH (op_name, "times")) @@ -234,9 +223,8 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_TIMES_UINT64) ; if (type == GrB_FP32 ) return (GrB_TIMES_FP32 ) ; if (type == GrB_FP64 ) return (GrB_TIMES_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_TIMES_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_TIMES_FC64 ) ; } else if (MATCH (op_name, "/") || MATCH (op_name, "div")) @@ -253,9 +241,8 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_DIV_UINT64) ; if (type == GrB_FP32 ) return (GrB_DIV_FP32 ) ; if (type == GrB_FP64 ) return (GrB_DIV_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_DIV_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_DIV_FC64 ) ; } else if (MATCH (op_name, "\\") || MATCH (op_name, "rdiv")) @@ -272,9 +259,8 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GxB_RDIV_UINT64) ; if (type == GrB_FP32 ) return (GxB_RDIV_FP32 ) ; if (type == GrB_FP64 ) return (GxB_RDIV_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_RDIV_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_RDIV_FC64 ) ; } else if (MATCH (op_name, "iseq")) @@ -291,9 +277,8 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GxB_ISEQ_UINT64) ; if (type == GrB_FP32 ) return (GxB_ISEQ_FP32 ) ; if (type == GrB_FP64 ) return (GxB_ISEQ_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_ISEQ_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_ISEQ_FC64 ) ; } else if (MATCH (op_name, "isne")) @@ -310,9 +295,8 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GxB_ISNE_UINT64) ; if (type == GrB_FP32 ) return (GxB_ISNE_FP32 ) ; if (type == GrB_FP64 ) return (GxB_ISNE_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_ISNE_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_ISNE_FC64 ) ; } else if (MATCH (op_name, "isgt")) @@ -329,9 +313,6 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GxB_ISGT_UINT64) ; if (type == GrB_FP32 ) return (GxB_ISGT_FP32 ) ; if (type == GrB_FP64 ) return (GxB_ISGT_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif } else if (MATCH (op_name, "islt")) @@ -348,9 +329,6 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GxB_ISLT_UINT64) ; if (type == GrB_FP32 ) return (GxB_ISLT_FP32 ) ; if (type == GrB_FP64 ) return (GxB_ISLT_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif } else if (MATCH (op_name, "isge")) @@ -367,9 +345,6 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GxB_ISGE_UINT64) ; if (type == GrB_FP32 ) return (GxB_ISGE_FP32 ) ; if (type == GrB_FP64 ) return (GxB_ISGE_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif } else if (MATCH (op_name, "isle")) @@ -386,15 +361,12 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GxB_ISLE_UINT64) ; if (type == GrB_FP32 ) return (GxB_ISLE_FP32 ) ; if (type == GrB_FP64 ) return (GxB_ISLE_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif } else if (MATCH (op_name, "==") || MATCH (op_name, "eq")) { - if (type == GrB_BOOL ) return (GrB_EQ_BOOL ) ; + if (type == GrB_BOOL ) return (GrB_EQ_BOOL ) ; // == GrB_LXNOR if (type == GrB_INT8 ) return (GrB_EQ_INT8 ) ; if (type == GrB_INT16 ) return (GrB_EQ_INT16 ) ; if (type == GrB_INT32 ) return (GrB_EQ_INT32 ) ; @@ -405,9 +377,8 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_EQ_UINT64) ; if (type == GrB_FP32 ) return (GrB_EQ_FP32 ) ; if (type == GrB_FP64 ) return (GrB_EQ_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_EQ_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_EQ_FC64 ) ; } else if (MATCH (op_name, "~=") || MATCH (op_name, "ne")) @@ -424,9 +395,8 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_NE_UINT64) ; if (type == GrB_FP32 ) return (GrB_NE_FP32 ) ; if (type == GrB_FP64 ) return (GrB_NE_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_NE_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_NE_FC64 ) ; } else if (MATCH (op_name, ">") || MATCH (op_name, "gt")) @@ -443,9 +413,6 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_GT_UINT64) ; if (type == GrB_FP32 ) return (GrB_GT_FP32 ) ; if (type == GrB_FP64 ) return (GrB_GT_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif } else if (MATCH (op_name, "<") || MATCH (op_name, "lt")) @@ -462,9 +429,6 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_LT_UINT64) ; if (type == GrB_FP32 ) return (GrB_LT_FP32 ) ; if (type == GrB_FP64 ) return (GrB_LT_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif } else if (MATCH (op_name, ">=") || MATCH (op_name, "ge")) @@ -481,9 +445,6 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_GE_UINT64) ; if (type == GrB_FP32 ) return (GrB_GE_FP32 ) ; if (type == GrB_FP64 ) return (GrB_GE_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif } else if (MATCH (op_name, "<=") || MATCH (op_name, "le")) @@ -500,9 +461,6 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GrB_LE_UINT64) ; if (type == GrB_FP32 ) return (GrB_LE_FP32 ) ; if (type == GrB_FP64 ) return (GrB_LE_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif } else if (MATCH (op_name, "||") || MATCH (op_name, "|") || @@ -520,9 +478,6 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GxB_LOR_UINT64) ; if (type == GrB_FP32 ) return (GxB_LOR_FP32 ) ; if (type == GrB_FP64 ) return (GxB_LOR_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif } else if (MATCH (op_name, "&&") || MATCH (op_name, "&") || @@ -540,9 +495,6 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GxB_LAND_UINT64) ; if (type == GrB_FP32 ) return (GxB_LAND_FP32 ) ; if (type == GrB_FP64 ) return (GxB_LAND_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif } else if (MATCH (op_name, "xor") || MATCH (op_name, "lxor")) @@ -559,9 +511,183 @@ GrB_BinaryOp gb_string_and_type_to_binop // return op from string and type if (type == GrB_UINT64) return (GxB_LXOR_UINT64) ; if (type == GrB_FP32 ) return (GxB_LXOR_FP32 ) ; if (type == GrB_FP64 ) return (GxB_LXOR_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + + } + else if (MATCH (op_name, "lxnor") || MATCH (op_name, "xnor")) + { + + if (type == GrB_BOOL ) return (GrB_LXNOR ) ; // == GrB_EQ_BOOL + + } + else if (MATCH (op_name, "atan2")) + { + + if (type == GrB_FP32 ) return (GxB_ATAN2_FP32 ) ; + if (type == GrB_FP64 ) return (GxB_ATAN2_FP64 ) ; + + } + else if (MATCH (op_name, "hypot")) + { + + if (type == GrB_FP32 ) return (GxB_HYPOT_FP32 ) ; + if (type == GrB_FP64 ) return (GxB_HYPOT_FP64 ) ; + + } + else if (MATCH (op_name, "fmod")) + { + + if (type == GrB_FP32 ) return (GxB_FMOD_FP32 ) ; + if (type == GrB_FP64 ) return (GxB_FMOD_FP64 ) ; + + } + else if (MATCH (op_name, "remainder")) + { + + if (type == GrB_FP32 ) return (GxB_REMAINDER_FP32 ) ; + if (type == GrB_FP64 ) return (GxB_REMAINDER_FP64 ) ; + + } + else if (MATCH (op_name, "copysign")) + { + + if (type == GrB_FP32 ) return (GxB_COPYSIGN_FP32 ) ; + if (type == GrB_FP64 ) return (GxB_COPYSIGN_FP64 ) ; + + } + else if (MATCH (op_name, "cmplx")) + { + + if (type == GrB_FP32 ) return (GxB_CMPLX_FP32 ) ; + if (type == GrB_FP64 ) return (GxB_CMPLX_FP64 ) ; + + } + else if (MATCH (op_name, "ldexp") || MATCH (op_name, "pow2")) + { + + if (type == GrB_FP32 ) return (GxB_LDEXP_FP32 ) ; + if (type == GrB_FP64 ) return (GxB_LDEXP_FP64 ) ; + + } + else if (MATCH (op_name, "pow")) + { + + if (type == GrB_BOOL ) return (GxB_POW_BOOL ) ; + if (type == GrB_INT8 ) return (GxB_POW_INT8 ) ; + if (type == GrB_INT16 ) return (GxB_POW_INT16 ) ; + if (type == GrB_INT32 ) return (GxB_POW_INT32 ) ; + if (type == GrB_INT64 ) return (GxB_POW_INT64 ) ; + if (type == GrB_UINT8 ) return (GxB_POW_UINT8 ) ; + if (type == GrB_UINT16) return (GxB_POW_UINT16) ; + if (type == GrB_UINT32) return (GxB_POW_UINT32) ; + if (type == GrB_UINT64) return (GxB_POW_UINT64) ; + if (type == GrB_FP32 ) return (GxB_POW_FP32 ) ; + if (type == GrB_FP64 ) return (GxB_POW_FP64 ) ; + if (type == GxB_FC32 ) return (GxB_POW_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_POW_FC64 ) ; + + } + else if (MATCH (op_name, "bitor")) + { + + if (type == GrB_INT8 ) return (GrB_BOR_INT8 ) ; + if (type == GrB_INT16 ) return (GrB_BOR_INT16 ) ; + if (type == GrB_INT32 ) return (GrB_BOR_INT32 ) ; + if (type == GrB_INT64 ) return (GrB_BOR_INT64 ) ; + if (type == GrB_UINT8 ) return (GrB_BOR_UINT8 ) ; + if (type == GrB_UINT16) return (GrB_BOR_UINT16) ; + if (type == GrB_UINT32) return (GrB_BOR_UINT32) ; + if (type == GrB_UINT64) return (GrB_BOR_UINT64) ; + + } + else if (MATCH (op_name, "bitand")) + { + + if (type == GrB_INT8 ) return (GrB_BAND_INT8 ) ; + if (type == GrB_INT16 ) return (GrB_BAND_INT16 ) ; + if (type == GrB_INT32 ) return (GrB_BAND_INT32 ) ; + if (type == GrB_INT64 ) return (GrB_BAND_INT64 ) ; + if (type == GrB_UINT8 ) return (GrB_BAND_UINT8 ) ; + if (type == GrB_UINT16) return (GrB_BAND_UINT16) ; + if (type == GrB_UINT32) return (GrB_BAND_UINT32) ; + if (type == GrB_UINT64) return (GrB_BAND_UINT64) ; + + } + else if (MATCH (op_name, "bitxor")) + { + + if (type == GrB_INT8 ) return (GrB_BXOR_INT8 ) ; + if (type == GrB_INT16 ) return (GrB_BXOR_INT16 ) ; + if (type == GrB_INT32 ) return (GrB_BXOR_INT32 ) ; + if (type == GrB_INT64 ) return (GrB_BXOR_INT64 ) ; + if (type == GrB_UINT8 ) return (GrB_BXOR_UINT8 ) ; + if (type == GrB_UINT16) return (GrB_BXOR_UINT16) ; + if (type == GrB_UINT32) return (GrB_BXOR_UINT32) ; + if (type == GrB_UINT64) return (GrB_BXOR_UINT64) ; + + } + else if (MATCH (op_name, "bitxnor")) + { + + if (type == GrB_INT8 ) return (GrB_BXNOR_INT8 ) ; + if (type == GrB_INT16 ) return (GrB_BXNOR_INT16 ) ; + if (type == GrB_INT32 ) return (GrB_BXNOR_INT32 ) ; + if (type == GrB_INT64 ) return (GrB_BXNOR_INT64 ) ; + if (type == GrB_UINT8 ) return (GrB_BXNOR_UINT8 ) ; + if (type == GrB_UINT16) return (GrB_BXNOR_UINT16) ; + if (type == GrB_UINT32) return (GrB_BXNOR_UINT32) ; + if (type == GrB_UINT64) return (GrB_BXNOR_UINT64) ; + + } + else if (MATCH (op_name, "bitget")) + { + + if (type == GrB_INT8 ) return (GxB_BGET_INT8 ) ; + if (type == GrB_INT16 ) return (GxB_BGET_INT16 ) ; + if (type == GrB_INT32 ) return (GxB_BGET_INT32 ) ; + if (type == GrB_INT64 ) return (GxB_BGET_INT64 ) ; + if (type == GrB_UINT8 ) return (GxB_BGET_UINT8 ) ; + if (type == GrB_UINT16) return (GxB_BGET_UINT16) ; + if (type == GrB_UINT32) return (GxB_BGET_UINT32) ; + if (type == GrB_UINT64) return (GxB_BGET_UINT64) ; + + } + else if (MATCH (op_name, "bitset")) + { + + if (type == GrB_INT8 ) return (GxB_BSET_INT8 ) ; + if (type == GrB_INT16 ) return (GxB_BSET_INT16 ) ; + if (type == GrB_INT32 ) return (GxB_BSET_INT32 ) ; + if (type == GrB_INT64 ) return (GxB_BSET_INT64 ) ; + if (type == GrB_UINT8 ) return (GxB_BSET_UINT8 ) ; + if (type == GrB_UINT16) return (GxB_BSET_UINT16) ; + if (type == GrB_UINT32) return (GxB_BSET_UINT32) ; + if (type == GrB_UINT64) return (GxB_BSET_UINT64) ; + + } + else if (MATCH (op_name, "bitclr")) + { + + if (type == GrB_INT8 ) return (GxB_BCLR_INT8 ) ; + if (type == GrB_INT16 ) return (GxB_BCLR_INT16 ) ; + if (type == GrB_INT32 ) return (GxB_BCLR_INT32 ) ; + if (type == GrB_INT64 ) return (GxB_BCLR_INT64 ) ; + if (type == GrB_UINT8 ) return (GxB_BCLR_UINT8 ) ; + if (type == GrB_UINT16) return (GxB_BCLR_UINT16) ; + if (type == GrB_UINT32) return (GxB_BCLR_UINT32) ; + if (type == GrB_UINT64) return (GxB_BCLR_UINT64) ; + + } + else if (MATCH (op_name, "bitshift")) + { + + if (type == GrB_INT8 ) return (GxB_BSHIFT_INT8 ) ; + if (type == GrB_INT16 ) return (GxB_BSHIFT_INT16 ) ; + if (type == GrB_INT32 ) return (GxB_BSHIFT_INT32 ) ; + if (type == GrB_INT64 ) return (GxB_BSHIFT_INT64 ) ; + if (type == GrB_UINT8 ) return (GxB_BSHIFT_UINT8 ) ; + if (type == GrB_UINT16) return (GxB_BSHIFT_UINT16) ; + if (type == GrB_UINT32) return (GxB_BSHIFT_UINT32) ; + if (type == GrB_UINT64) return (GxB_BSHIFT_UINT64) ; } diff --git a/GraphBLAS/@GrB/private/util/gb_string_and_type_to_unop.c b/GraphBLAS/@GrB/private/util/gb_string_and_type_to_unop.c index c2859b0e89..2454cbd446 100644 --- a/GraphBLAS/@GrB/private/util/gb_string_and_type_to_unop.c +++ b/GraphBLAS/@GrB/private/util/gb_string_and_type_to_unop.c @@ -9,18 +9,46 @@ #include "gb_matlab.h" -// op_name: a MATLAB string defining the operator name (6 kinds): -// 'identity', 'ainv' 'minv', 'lnot', 'one', 'abs'. +// op_name: a MATLAB string defining the operator name. -// The following equivalent synonyms are available: -// ainv - negate -// lnot ~ not -// one 1 +// For all 13 types: +// identity, ainv, minv, one, abs +// (for complex, abs returns a real result) + +// For all 11 real types: (result is same type as input) +// lnot + +// For 4 floating-point types (real & complex)x(single & double) +// (result is same type as input): +// sqrt, log, exp, +// sin, cos, tan, acos, asin, atan, +// sinh, cosh, tanh, acosh, asinh, atanh, +// signum, ceil, floor, round, trunc, exp2, expm1, log10, log1p, log2 -// Total # of ops: 6*11 = 66, not including GrB_LNOT, -// which is equivalent to GxB_LNOT_BOOL. +// for complex only: +// creal, cimag, carg (result is real) +// conj (result is complex) -// FUTURE: add complex unary operators. +// For all 4 floating-point types (result is logical) +// isinf, isnan, isfinite + +// For single and double: +// lgamma, tgamma, erf, erfc, frexpx, frexpe (result same type as input) + +// for integer types only: +// bitcmp + +// The following equivalent synonyms are available: +// identity + uplus +// ainv - uminus negate +// lnot ~ not +// one 1 +// creal real +// cimag imag +// carg angle +// lgamma gammaln +// tgamma gamma +// exp2 pow2 GrB_UnaryOp gb_string_and_type_to_unop // return op from string and type ( @@ -31,7 +59,8 @@ GrB_UnaryOp gb_string_and_type_to_unop // return op from string and type CHECK_ERROR (type == NULL, "unsupported type") ; - if (MATCH (op_name, "identity")) + if (MATCH (op_name, "identity") || MATCH (op_name, "+") || + MATCH (op_name, "uplus")) { if (type == GrB_BOOL ) return (GrB_IDENTITY_BOOL ) ; @@ -45,13 +74,12 @@ GrB_UnaryOp gb_string_and_type_to_unop // return op from string and type if (type == GrB_UINT64) return (GrB_IDENTITY_UINT64) ; if (type == GrB_FP32 ) return (GrB_IDENTITY_FP32 ) ; if (type == GrB_FP64 ) return (GrB_IDENTITY_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (... ) ; - #endif + if (type == GxB_FC32 ) return (GxB_IDENTITY_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_IDENTITY_FC64 ) ; } - else if (MATCH (op_name, "ainv") || MATCH (op_name, "-") || - MATCH (op_name, "negate")) + else if (MATCH (op_name, "ainv" ) || MATCH (op_name, "-") || + MATCH (op_name, "negate") || MATCH (op_name, "uminus")) { if (type == GrB_BOOL ) return (GrB_AINV_BOOL ) ; @@ -65,9 +93,8 @@ GrB_UnaryOp gb_string_and_type_to_unop // return op from string and type if (type == GrB_UINT64) return (GrB_AINV_UINT64) ; if (type == GrB_FP32 ) return (GrB_AINV_FP32 ) ; if (type == GrB_FP64 ) return (GrB_AINV_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_AINV_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_AINV_FC64 ) ; } else if (MATCH (op_name, "minv")) @@ -84,9 +111,8 @@ GrB_UnaryOp gb_string_and_type_to_unop // return op from string and type if (type == GrB_UINT64) return (GrB_MINV_UINT64) ; if (type == GrB_FP32 ) return (GrB_MINV_FP32 ) ; if (type == GrB_FP64 ) return (GrB_MINV_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_MINV_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_MINV_FC64 ) ; } else if (MATCH (op_name, "lnot") || MATCH (op_name, "~") || @@ -104,9 +130,6 @@ GrB_UnaryOp gb_string_and_type_to_unop // return op from string and type if (type == GrB_UINT64) return (GxB_LNOT_UINT64) ; if (type == GrB_FP32 ) return (GxB_LNOT_FP32 ) ; if (type == GrB_FP64 ) return (GxB_LNOT_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif } else if (MATCH (op_name, "one") || MATCH (op_name, "1")) @@ -123,9 +146,8 @@ GrB_UnaryOp gb_string_and_type_to_unop // return op from string and type if (type == GrB_UINT64) return (GxB_ONE_UINT64) ; if (type == GrB_FP32 ) return (GxB_ONE_FP32 ) ; if (type == GrB_FP64 ) return (GxB_ONE_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_ONE_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_ONE_FC64 ) ; } else if (MATCH (op_name, "abs")) @@ -142,9 +164,343 @@ GrB_UnaryOp gb_string_and_type_to_unop // return op from string and type if (type == GrB_UINT64) return (GxB_ABS_UINT64) ; if (type == GrB_FP32 ) return (GxB_ABS_FP32 ) ; if (type == GrB_FP64 ) return (GxB_ABS_FP64 ) ; - #ifdef GB_COMPLEX_TYPE - if (type == gb_complex_type) return (...) ; - #endif + if (type == GxB_FC32 ) return (GxB_ABS_FC32 ) ; + if (type == GxB_FC64 ) return (GxB_ABS_FC64 ) ; + + } + else if (MATCH (op_name, "sqrt")) + { + + if (type == GrB_FP32 ) return (GxB_SQRT_FP32) ; + if (type == GrB_FP64 ) return (GxB_SQRT_FP64) ; + if (type == GxB_FC32 ) return (GxB_SQRT_FC32) ; + if (type == GxB_FC64 ) return (GxB_SQRT_FC64) ; + + } + else if (MATCH (op_name, "log")) + { + + if (type == GrB_FP32 ) return (GxB_LOG_FP32) ; + if (type == GrB_FP64 ) return (GxB_LOG_FP64) ; + if (type == GxB_FC32 ) return (GxB_LOG_FC32) ; + if (type == GxB_FC64 ) return (GxB_LOG_FC64) ; + + } + else if (MATCH (op_name, "exp")) + { + + if (type == GrB_FP32 ) return (GxB_EXP_FP32) ; + if (type == GrB_FP64 ) return (GxB_EXP_FP64) ; + if (type == GxB_FC32 ) return (GxB_EXP_FC32) ; + if (type == GxB_FC64 ) return (GxB_EXP_FC64) ; + + } + else if (MATCH (op_name, "sin")) + { + + if (type == GrB_FP32 ) return (GxB_SIN_FP32) ; + if (type == GrB_FP64 ) return (GxB_SIN_FP64) ; + if (type == GxB_FC32 ) return (GxB_SIN_FC32) ; + if (type == GxB_FC64 ) return (GxB_SIN_FC64) ; + + } + else if (MATCH (op_name, "cos")) + { + + if (type == GrB_FP32 ) return (GxB_COS_FP32) ; + if (type == GrB_FP64 ) return (GxB_COS_FP64) ; + if (type == GxB_FC32 ) return (GxB_COS_FC32) ; + if (type == GxB_FC64 ) return (GxB_COS_FC64) ; + + } + else if (MATCH (op_name, "tan")) + { + + if (type == GrB_FP32 ) return (GxB_TAN_FP32) ; + if (type == GrB_FP64 ) return (GxB_TAN_FP64) ; + if (type == GxB_FC32 ) return (GxB_TAN_FC32) ; + if (type == GxB_FC64 ) return (GxB_TAN_FC64) ; + + } + else if (MATCH (op_name, "asin")) + { + + if (type == GrB_FP32 ) return (GxB_ASIN_FP32) ; + if (type == GrB_FP64 ) return (GxB_ASIN_FP64) ; + if (type == GxB_FC32 ) return (GxB_ASIN_FC32) ; + if (type == GxB_FC64 ) return (GxB_ASIN_FC64) ; + + } + else if (MATCH (op_name, "acos")) + { + + if (type == GrB_FP32 ) return (GxB_ACOS_FP32) ; + if (type == GrB_FP64 ) return (GxB_ACOS_FP64) ; + if (type == GxB_FC32 ) return (GxB_ACOS_FC32) ; + if (type == GxB_FC64 ) return (GxB_ACOS_FC64) ; + + } + else if (MATCH (op_name, "atan")) + { + + if (type == GrB_FP32 ) return (GxB_ATAN_FP32) ; + if (type == GrB_FP64 ) return (GxB_ATAN_FP64) ; + if (type == GxB_FC32 ) return (GxB_ATAN_FC32) ; + if (type == GxB_FC64 ) return (GxB_ATAN_FC64) ; + + } + else if (MATCH (op_name, "sinh")) + { + + if (type == GrB_FP32 ) return (GxB_SINH_FP32) ; + if (type == GrB_FP64 ) return (GxB_SINH_FP64) ; + if (type == GxB_FC32 ) return (GxB_SINH_FC32) ; + if (type == GxB_FC64 ) return (GxB_SINH_FC64) ; + + } + else if (MATCH (op_name, "cosh")) + { + + if (type == GrB_FP32 ) return (GxB_COSH_FP32) ; + if (type == GrB_FP64 ) return (GxB_COSH_FP64) ; + if (type == GxB_FC32 ) return (GxB_COSH_FC32) ; + if (type == GxB_FC64 ) return (GxB_COSH_FC64) ; + + } + else if (MATCH (op_name, "tanh")) + { + + if (type == GrB_FP32 ) return (GxB_TANH_FP32) ; + if (type == GrB_FP64 ) return (GxB_TANH_FP64) ; + if (type == GxB_FC32 ) return (GxB_TANH_FC32) ; + if (type == GxB_FC64 ) return (GxB_TANH_FC64) ; + + } + else if (MATCH (op_name, "asinh")) + { + + if (type == GrB_FP32 ) return (GxB_ASINH_FP32) ; + if (type == GrB_FP64 ) return (GxB_ASINH_FP64) ; + if (type == GxB_FC32 ) return (GxB_ASINH_FC32) ; + if (type == GxB_FC64 ) return (GxB_ASINH_FC64) ; + + } + else if (MATCH (op_name, "acosh")) + { + + if (type == GrB_FP32 ) return (GxB_ACOSH_FP32) ; + if (type == GrB_FP64 ) return (GxB_ACOSH_FP64) ; + if (type == GxB_FC32 ) return (GxB_ACOSH_FC32) ; + if (type == GxB_FC64 ) return (GxB_ACOSH_FC64) ; + + } + else if (MATCH (op_name, "atanh")) + { + + if (type == GrB_FP32 ) return (GxB_ATANH_FP32) ; + if (type == GrB_FP64 ) return (GxB_ATANH_FP64) ; + if (type == GxB_FC32 ) return (GxB_ATANH_FC32) ; + if (type == GxB_FC64 ) return (GxB_ATANH_FC64) ; + + } + else if (MATCH (op_name, "sign") || MATCH (op_name, "signum")) + { + + if (type == GrB_FP32 ) return (GxB_SIGNUM_FP32) ; + if (type == GrB_FP64 ) return (GxB_SIGNUM_FP64) ; + if (type == GxB_FC32 ) return (GxB_SIGNUM_FC32) ; + if (type == GxB_FC64 ) return (GxB_SIGNUM_FC64) ; + + } + else if (MATCH (op_name, "ceil")) + { + + if (type == GrB_FP32 ) return (GxB_CEIL_FP32) ; + if (type == GrB_FP64 ) return (GxB_CEIL_FP64) ; + if (type == GxB_FC32 ) return (GxB_CEIL_FC32) ; + if (type == GxB_FC64 ) return (GxB_CEIL_FC64) ; + + } + else if (MATCH (op_name, "floor")) + { + + if (type == GrB_FP32 ) return (GxB_FLOOR_FP32) ; + if (type == GrB_FP64 ) return (GxB_FLOOR_FP64) ; + if (type == GxB_FC32 ) return (GxB_FLOOR_FC32) ; + if (type == GxB_FC64 ) return (GxB_FLOOR_FC64) ; + + } + else if (MATCH (op_name, "round")) + { + + if (type == GrB_FP32 ) return (GxB_ROUND_FP32) ; + if (type == GrB_FP64 ) return (GxB_ROUND_FP64) ; + if (type == GxB_FC32 ) return (GxB_ROUND_FC32) ; + if (type == GxB_FC64 ) return (GxB_ROUND_FC64) ; + + } + else if (MATCH (op_name, "trunc") || MATCH (op_name, "fix")) + { + + if (type == GrB_FP32 ) return (GxB_TRUNC_FP32) ; + if (type == GrB_FP64 ) return (GxB_TRUNC_FP64) ; + if (type == GxB_FC32 ) return (GxB_TRUNC_FC32) ; + if (type == GxB_FC64 ) return (GxB_TRUNC_FC64) ; + + } + else if (MATCH (op_name, "exp2") || MATCH (op_name, "pow2")) + { + + if (type == GrB_FP32 ) return (GxB_EXP2_FP32) ; + if (type == GrB_FP64 ) return (GxB_EXP2_FP64) ; + if (type == GxB_FC32 ) return (GxB_EXP2_FC32) ; + if (type == GxB_FC64 ) return (GxB_EXP2_FC64) ; + + } + else if (MATCH (op_name, "expm1")) + { + + if (type == GrB_FP32 ) return (GxB_EXPM1_FP32) ; + if (type == GrB_FP64 ) return (GxB_EXPM1_FP64) ; + if (type == GxB_FC32 ) return (GxB_EXPM1_FC32) ; + if (type == GxB_FC64 ) return (GxB_EXPM1_FC64) ; + + } + else if (MATCH (op_name, "log10")) + { + + if (type == GrB_FP32 ) return (GxB_LOG10_FP32) ; + if (type == GrB_FP64 ) return (GxB_LOG10_FP64) ; + if (type == GxB_FC32 ) return (GxB_LOG10_FC32) ; + if (type == GxB_FC64 ) return (GxB_LOG10_FC64) ; + + } + else if (MATCH (op_name, "log1p")) + { + + if (type == GrB_FP32 ) return (GxB_LOG1P_FP32) ; + if (type == GrB_FP64 ) return (GxB_LOG1P_FP64) ; + if (type == GxB_FC32 ) return (GxB_LOG1P_FC32) ; + if (type == GxB_FC64 ) return (GxB_LOG1P_FC64) ; + + } + else if (MATCH (op_name, "log2")) + { + + if (type == GrB_FP32 ) return (GxB_LOG2_FP32) ; + if (type == GrB_FP64 ) return (GxB_LOG2_FP64) ; + if (type == GxB_FC32 ) return (GxB_LOG2_FC32) ; + if (type == GxB_FC64 ) return (GxB_LOG2_FC64) ; + + } + else if (MATCH (op_name, "lgamma") || MATCH (op_name, "gammaln")) + { + + if (type == GrB_FP32 ) return (GxB_LGAMMA_FP32) ; + if (type == GrB_FP64 ) return (GxB_LGAMMA_FP64) ; + + } + else if (MATCH (op_name, "tgamma") || MATCH (op_name, "gamma")) + { + + if (type == GrB_FP32 ) return (GxB_TGAMMA_FP32) ; + if (type == GrB_FP64 ) return (GxB_TGAMMA_FP64) ; + + } + else if (MATCH (op_name, "erf")) + { + + if (type == GrB_FP32 ) return (GxB_ERF_FP32) ; + if (type == GrB_FP64 ) return (GxB_ERF_FP64) ; + + } + else if (MATCH (op_name, "erfc")) + { + + if (type == GrB_FP32 ) return (GxB_ERFC_FP32) ; + if (type == GrB_FP64 ) return (GxB_ERFC_FP64) ; + + } + else if (MATCH (op_name, "conj")) + { + + if (type == GxB_FC32 ) return (GxB_CONJ_FC32) ; + if (type == GxB_FC64 ) return (GxB_CONJ_FC64) ; + + } + else if (MATCH (op_name, "creal") || MATCH (op_name, "real")) + { + + if (type == GxB_FC32 ) return (GxB_CREAL_FC32) ; + if (type == GxB_FC64 ) return (GxB_CREAL_FC64) ; + + } + else if (MATCH (op_name, "cimag") || MATCH (op_name, "imag")) + { + + if (type == GxB_FC32 ) return (GxB_CIMAG_FC32) ; + if (type == GxB_FC64 ) return (GxB_CIMAG_FC64) ; + + } + else if (MATCH (op_name, "carg") || MATCH (op_name, "angle")) + { + + if (type == GxB_FC32 ) return (GxB_CARG_FC32) ; + if (type == GxB_FC64 ) return (GxB_CARG_FC64) ; + + } + else if (MATCH (op_name, "isinf")) + { + + if (type == GrB_FP32 ) return (GxB_ISINF_FP32) ; + if (type == GrB_FP64 ) return (GxB_ISINF_FP64) ; + if (type == GxB_FC32 ) return (GxB_ISINF_FC32) ; + if (type == GxB_FC64 ) return (GxB_ISINF_FC64) ; + + } + else if (MATCH (op_name, "isnan")) + { + + if (type == GrB_FP32 ) return (GxB_ISNAN_FP32) ; + if (type == GrB_FP64 ) return (GxB_ISNAN_FP64) ; + if (type == GxB_FC32 ) return (GxB_ISNAN_FC32) ; + if (type == GxB_FC64 ) return (GxB_ISNAN_FC64) ; + + } + else if (MATCH (op_name, "isfinite")) + { + + if (type == GrB_FP32 ) return (GxB_ISFINITE_FP32) ; + if (type == GrB_FP64 ) return (GxB_ISFINITE_FP64) ; + if (type == GxB_FC32 ) return (GxB_ISFINITE_FC32) ; + if (type == GxB_FC64 ) return (GxB_ISFINITE_FC64) ; + + } + else if (MATCH (op_name, "frexpx")) + { + + if (type == GrB_FP32 ) return (GxB_FREXPX_FP32) ; + if (type == GrB_FP64 ) return (GxB_FREXPX_FP64) ; + + } + else if (MATCH (op_name, "frexpe")) + { + + if (type == GrB_FP32 ) return (GxB_FREXPE_FP32) ; + if (type == GrB_FP64 ) return (GxB_FREXPE_FP64) ; + + } + else if (MATCH (op_name, "bitcmp") || MATCH (op_name, "bitnot")) + { + + if (type == GrB_INT8 ) return (GrB_BNOT_INT8 ) ; + if (type == GrB_INT16 ) return (GrB_BNOT_INT16 ) ; + if (type == GrB_INT32 ) return (GrB_BNOT_INT32 ) ; + if (type == GrB_INT64 ) return (GrB_BNOT_INT64 ) ; + if (type == GrB_UINT8 ) return (GrB_BNOT_UINT8 ) ; + if (type == GrB_UINT16) return (GrB_BNOT_UINT16) ; + if (type == GrB_UINT32) return (GrB_BNOT_UINT32) ; + if (type == GrB_UINT64) return (GrB_BNOT_UINT64) ; } diff --git a/GraphBLAS/@GrB/private/util/gb_string_to_binop.c b/GraphBLAS/@GrB/private/util/gb_string_to_binop.c index b23ad81d80..d8f63790ed 100644 --- a/GraphBLAS/@GrB/private/util/gb_string_to_binop.c +++ b/GraphBLAS/@GrB/private/util/gb_string_to_binop.c @@ -13,16 +13,11 @@ // GrB_PLUS_FP64 operator. The type is optional. If not present, it defaults // to the default_type parameter. -// type: a MATLAB string defining one of 11 operator types: -// 'logical', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', -// 'uint64', 'single', and 'double' - -// FUTURE: The 'complex' type will be added. - GrB_BinaryOp gb_string_to_binop // return binary operator from a string ( char *opstring, // string defining the operator - const GrB_Type default_type // default type if not in the string + const GrB_Type atype, // type of A + const GrB_Type btype // type of B ) { @@ -48,7 +43,7 @@ GrB_BinaryOp gb_string_to_binop // return binary operator from a string GrB_Type type ; if (op_typename == NULL) { - type = default_type ; + type = gb_default_type (atype, btype) ; } else { diff --git a/GraphBLAS/@GrB/private/util/gb_string_to_monoid.c b/GraphBLAS/@GrB/private/util/gb_string_to_monoid.c index c199b07475..803861720e 100644 --- a/GraphBLAS/@GrB/private/util/gb_string_to_monoid.c +++ b/GraphBLAS/@GrB/private/util/gb_string_to_monoid.c @@ -10,20 +10,17 @@ #include "gb_matlab.h" // The string has the form op_name.op_type. For example '+.double' is -// GxB_PLUS_FP64_MONOID. The type is optional. If not present, it defaults +// GrB_PLUS_MONOID_FP64. The type is optional. If not present, it defaults // to the default_type parameter. GrB_Monoid gb_string_to_monoid // return monoid from a string ( char *opstring, // string defining the operator - const GrB_Type default_type // default type if not in the string + const GrB_Type type // default type if not in the string ) -{ +{ - //-------------------------------------------------------------------------- // get the binary operator and convert to a monoid - //-------------------------------------------------------------------------- - - return (gb_binop_to_monoid (gb_string_to_binop (opstring, default_type))) ; + return (gb_binop_to_monoid (gb_string_to_binop (opstring, type, type))) ; } diff --git a/GraphBLAS/@GrB/private/util/gb_string_to_semiring.c b/GraphBLAS/@GrB/private/util/gb_string_to_semiring.c index c7f923e830..f45991280e 100644 --- a/GraphBLAS/@GrB/private/util/gb_string_to_semiring.c +++ b/GraphBLAS/@GrB/private/util/gb_string_to_semiring.c @@ -9,15 +9,13 @@ // Only built-in GraphBLAS types and operators are supported. -// FUTURE: complex semirings - #include "gb_matlab.h" GrB_Semiring gb_string_to_semiring // return a semiring from a string ( char *semiring_string, // string defining the semiring - const GrB_Type default_type // default type if not in the string: - // type of x,y inputs to mult operator + const GrB_Type atype, // type of A + const GrB_Type btype // type of B ) { @@ -52,7 +50,7 @@ GrB_Semiring gb_string_to_semiring // return a semiring from a string GrB_Type mult_type ; if (mult_typename == NULL) { - mult_type = default_type ; + mult_type = gb_default_type (atype, btype) ; } else { diff --git a/GraphBLAS/@GrB/private/util/gb_string_to_type.c b/GraphBLAS/@GrB/private/util/gb_string_to_type.c index dc751b8d19..b722f45717 100644 --- a/GraphBLAS/@GrB/private/util/gb_string_to_type.c +++ b/GraphBLAS/@GrB/private/util/gb_string_to_type.c @@ -11,24 +11,32 @@ GrB_Type gb_string_to_type // return the GrB_Type from a string ( - const char *classname + const char *typename ) { - if (MATCH (classname, "logical" )) return (GrB_BOOL) ; - if (MATCH (classname, "int8" )) return (GrB_INT8) ; - if (MATCH (classname, "int16" )) return (GrB_INT16) ; - if (MATCH (classname, "int32" )) return (GrB_INT32) ; - if (MATCH (classname, "int64" )) return (GrB_INT64) ; - if (MATCH (classname, "uint8" )) return (GrB_UINT8) ; - if (MATCH (classname, "uint16" )) return (GrB_UINT16) ; - if (MATCH (classname, "uint32" )) return (GrB_UINT32) ; - if (MATCH (classname, "uint64" )) return (GrB_UINT64) ; - if (MATCH (classname, "single" )) return (GrB_FP32) ; - if (MATCH (classname, "double" )) return (GrB_FP64) ; - #ifdef GB_COMPLEX_TYPE - if (MATCH (classname, "complex" )) return (gb_complex_type) ; - #endif + if (MATCH (typename, "logical" )) return (GrB_BOOL) ; + if (MATCH (typename, "int8" )) return (GrB_INT8) ; + if (MATCH (typename, "int16" )) return (GrB_INT16) ; + if (MATCH (typename, "int32" )) return (GrB_INT32) ; + if (MATCH (typename, "int64" )) return (GrB_INT64) ; + if (MATCH (typename, "uint8" )) return (GrB_UINT8) ; + if (MATCH (typename, "uint16" )) return (GrB_UINT16) ; + if (MATCH (typename, "uint32" )) return (GrB_UINT32) ; + if (MATCH (typename, "uint64" )) return (GrB_UINT64) ; + if (MATCH (typename, "single" )) return (GrB_FP32) ; + if (MATCH (typename, "double" )) return (GrB_FP64) ; + + if (MATCH (typename, "single complex")) + { + return (GxB_FC32) ; + } + + if (MATCH (typename, "double complex") || + MATCH (typename, "complex")) + { + return (GxB_FC64) ; + } // The string is not a type, but this is not an error here. For example, // G = GrB (m,n,'double','by row') queries both its string input arguments diff --git a/GraphBLAS/@GrB/private/util/gb_string_to_unop.c b/GraphBLAS/@GrB/private/util/gb_string_to_unop.c index 605129d2aa..28fc7331e4 100644 --- a/GraphBLAS/@GrB/private/util/gb_string_to_unop.c +++ b/GraphBLAS/@GrB/private/util/gb_string_to_unop.c @@ -13,12 +13,6 @@ // GxB_ABS_FP64 operator. The type is optional. If not present, it defaults // to the default_type parameter. -// type: a MATLAB string defining one of 11 operator types: -// 'logical', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', -// 'uint64', 'single', and 'double' - -// FUTURE: The 'complex' type will be added. - GrB_UnaryOp gb_string_to_unop // return unary operator from a string ( char *opstring, // string defining the operator diff --git a/GraphBLAS/@GrB/private/util/gb_type_to_mxstring.c b/GraphBLAS/@GrB/private/util/gb_type_to_mxstring.c index cbab529a13..cd1318255b 100644 --- a/GraphBLAS/@GrB/private/util/gb_type_to_mxstring.c +++ b/GraphBLAS/@GrB/private/util/gb_type_to_mxstring.c @@ -26,12 +26,8 @@ GrB_Type gb_type_to_mxstring // return the MATLAB string from a GrB_Type else if (type == GrB_UINT64) return (mxCreateString ("uint64")) ; else if (type == GrB_FP32) return (mxCreateString ("single")) ; else if (type == GrB_FP64) return (mxCreateString ("double")) ; - #ifdef GB_COMPLEX_TYPE - else if (type == gb_complex_type) - { - return (mxCreateString ("complex")) ; - } - #endif + else if (type == GxB_FC32) return (mxCreateString ("single complex")) ; + else if (type == GxB_FC64) return (mxCreateString ("double complex")) ; else { ERROR ("unsupported type") ; diff --git a/GraphBLAS/@GrB/private/util/gb_typecast.c b/GraphBLAS/@GrB/private/util/gb_typecast.c index 9fa6f051f5..a508b658fd 100644 --- a/GraphBLAS/@GrB/private/util/gb_typecast.c +++ b/GraphBLAS/@GrB/private/util/gb_typecast.c @@ -42,15 +42,24 @@ GrB_Matrix gb_typecast // A = (type) S, where A is deep OK (GrB_Matrix_ncols (&ncols, S)) ; OK (GrB_Matrix_new (&A, type, nrows, ncols)) ; OK (GxB_Matrix_Option_set (A, GxB_FORMAT, fmt)) ; - - // create a descriptor with d.trans = transpose - GrB_Descriptor d ; - OK (GrB_Descriptor_new (&d)) ; - OK (GrB_Descriptor_set (d, GrB_INP0, GrB_TRAN)) ; - - // A = (type) S - OK (GrB_transpose (A, NULL, NULL, S, d)) ; - OK (GrB_Descriptor_free (&d)) ; + GrB_Type stype ; + OK (GxB_Matrix_type (&stype, S)) ; + + if (gb_is_integer (type) && gb_is_float (stype)) + { + // A = (type) round (S), using MATLAB rules for typecasting. + OK (GrB_Matrix_apply (A, NULL, NULL, gb_round_binop (stype), S, + NULL)) ; + } + else + { + // A = (type) S, no rounding. Use GraphBLAS typecasting if needed. + GrB_Descriptor d ; + OK (GrB_Descriptor_new (&d)) ; + OK (GrB_Descriptor_set (d, GrB_INP0, GrB_TRAN)) ; + OK (GrB_transpose (A, NULL, NULL, S, d)) ; + OK (GrB_Descriptor_free (&d)) ; + } } //-------------------------------------------------------------------------- diff --git a/GraphBLAS/@GrB/private/util/gb_usage.c b/GraphBLAS/@GrB/private/util/gb_usage.c index b72712b7bd..6af7d300ef 100644 --- a/GraphBLAS/@GrB/private/util/gb_usage.c +++ b/GraphBLAS/@GrB/private/util/gb_usage.c @@ -36,13 +36,10 @@ void gb_usage // check usage and make sure GrB.init has been called // MATLAB matrices are stored by column OK (GxB_Global_Option_set (GxB_FORMAT, GxB_BY_COL)) ; - // print short format by default - GB_Global_print_format_set (1) ; - // print 1-based indices GB_Global_print_one_based_set (true) ; - // for debug assertions only + // for debug only GB_Global_abort_function_set (gb_abort) ; } diff --git a/GraphBLAS/@GrB/prod.m b/GraphBLAS/@GrB/prod.m index b4db25a60b..0cb676ba3a 100644 --- a/GraphBLAS/@GrB/prod.m +++ b/GraphBLAS/@GrB/prod.m @@ -1,9 +1,9 @@ function C = prod (G, option) -%PROD Product of elements. -% C = prod (G), where G is an m-by-n GraphBLAS matrix, computes a 1-by-n -% row vector C where C(j) is the product of all entries in G(:,j). If G -% is a row or column vector, then prod (G) is a scalar product of all the -% entries in the vector. +%PROD product of elements. +% C = prod (G), where G is an m-by-n matrix, is a 1-by-n row vector C where +% C(j) is the product of all entries in G(:,j). If G is a row or column +% vector, then prod (G) is a scalar product of all the entries in the +% vector. % % C = prod (G,'all') takes the product of all elements of G to a single % scalar. @@ -15,57 +15,27 @@ % C = prod (G,2) takes the product of each row, resulting in an m-by-1 % column vector C where C(i) is the product of all entries in G(i,:). % -% The MATLAB prod (A, ... type, nanflag) allows for different types of -% products to be computed, and the NaN behavior can be specified. The -% GraphBLAS prod (G,...) uses only a type of 'native', and a nanflag of +% The built-in MATLAB prod (A, ... type, nanflag) allows for different +% kinds of products to be computed, and the NaN behavior can be specified. +% The GraphBLAS prod (G,...) uses only a type of 'native', and a nanflag of % 'includenan'. See 'help prod' for more details. % -% See also GrB/max, GrB/min, GrB/sum. +% See also GrB/all, GrB/max, GrB/min, GrB/sum. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -[m, n] = size (G) ; -desc = struct ('in0', 'transpose') ; -if (isequal (GrB.type (G), 'logical')) +G = G.opaque ; +type = gbtype (G) ; +if (isequal (type, 'logical')) op = '&.logical' ; else op = '*' ; end if (nargin == 1) - % C = prod (G); check if G is a row vector - if (isvector (G)) - % C = prod (G) for a vector G results in a scalar C - if (~GrB.isfull (G)) - C = GrB (0, GrB.type (G)) ; - else - C = GrB.reduce (op, G) ; - end - else - % C = prod (G) reduces each column to a scalar, - % giving a 1-by-n row vector. - coldegree = GrB.entries (G, 'col', 'degree') ; - C = (GrB.vreduce (op, G, desc) .* (coldegree == m))' ; - end -elseif (isequal (option, 'all')) - % C = prod (G, 'all'), reducing all entries to a scalar - if (~GrB.isfull (G)) - C = GrB (0, GrB.type (G)) ; - else - C = GrB.reduce (op, G) ; - end -elseif (isequal (option, 1)) - % C = prod (G,1) reduces each column to a scalar, - % giving a 1-by-n row vector. - coldegree = GrB.entries (G, 'col', 'degree') ; - C = (GrB.vreduce (op, G, desc) .* (coldegree == m))' ; -elseif (isequal (option, 2)) - % C = prod (G,2) reduces each row to a scalar, - % giving an m-by-1 column vector. - rowdegree = GrB.entries (G, 'row', 'degree') ; - C = GrB.vreduce (op, G) .* (rowdegree == n) ; + C = GrB (gb_prod (op, type, G)) ; else - gb_error ('unknown option') ; + C = GrB (gb_prod (op, type, G, option)) ; end diff --git a/GraphBLAS/@GrB/prune.m b/GraphBLAS/@GrB/prune.m index 8b97f42a05..98cee056a1 100644 --- a/GraphBLAS/@GrB/prune.m +++ b/GraphBLAS/@GrB/prune.m @@ -5,12 +5,29 @@ % % See also GrB/full, GrB.select, GrB.prune. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. if (nargin == 1) - C = GrB.select (G, 'nonzero') ; + id = 0 ; else - C = GrB.select (G, '~=', id) ; + id = gb_get_scalar (id) ; +end + +if (builtin ('issparse', G) && id == 0) + % a MATLAB sparse matrix 'never' contains explicit zeros, + % so no need to prune. C should be returned as a GraphBLAS + % matrix, however. + C = GrB (G) ; +else + if (isobject (G)) + % extract the contents of a GraphBLAS matrix + G = G.opaque ; + end + if (id == 0) + C = GrB (gbselect (G, 'nonzero')) ; + else + C = GrB (gbselect (G, '~=', id)) ; + end end diff --git a/GraphBLAS/@GrB/random.m b/GraphBLAS/@GrB/random.m index bc1f488dfa..b6620e2bcb 100644 --- a/GraphBLAS/@GrB/random.m +++ b/GraphBLAS/@GrB/random.m @@ -1,13 +1,10 @@ function C = random (varargin) -%GRB.RANDOM uniformly distributed random GraphBLAS matrix. +%GRB.RANDOM random sparse matrix. % C = GrB.random (A) has the same pattern as A, but with uniformly -% distributed random entries. If the same random seed is used, -% GrB.random (A) and the MATLAB sprand (A) produce the same result. +% distributed random entries. % % C = GrB.random (m, n, d) is a random m-by-n GraphBLAS matrix, with -% about d*m*n uniformly distributed entries. With the same inputs -% and same random seed, GrB.random and the MATLAB built-in sprand -% produce the same pattern, but the values differ. The entries are +% about d*m*n uniformly distributed entries. The entries are % constructed by computing d*m*n entries at random positions, and % then any duplicates are discarded, so if d is large or m*n is % small, then C will have fewer than d*m*n entries. The value of @@ -18,34 +15,42 @@ % Optional parameters may be used, in any order, after the A or m,n,d % arguments: % -% C = GrB.random (..., 'uniform') uses a uniform distribution +% C = GrB.random (..., 'uniform', ...) uses a uniform distribution % of values, with entries greater than zero and less than one. % -% C = GrB.random (..., 'normal') uses a normal distribution, like +% C = GrB.random (..., 'normal', ...) uses a normal distribution, like % the built-in MATLAB sprandn. % -% C = GrB.random (..., 'range', [lo hi]) changes the range of +% C = GrB.random (..., 'range', [lo hi], ...) changes the range of % the random numbers. If 'range' is not present, the default -% is double ([0 1]). The class of [lo hi] determines the type +% is double ([0 1]). The type of [lo hi] determines the type % of the random matrix C. If [lo hi] is logical, all entries % in the pattern are true. If [lo hi] is 'double' or 'single', % then if the random number generator (rand or randn) produces % a double random value of x, it is scaled to (hi-lo)*x+lo. If % [lo hi] is integer, then x becomes floor ((hi-lo+1)*x + lo), % which is then typecasted to the requested. integer type. This -% scaling applies to both the 'uniform' and 'normal' distribution. +% scaling applies to both the 'uniform' and 'normal' +% distribution. To construct a random complex matrix, pass in +% [lo hi] as single complex or double complex. +% % With the normal distribution, [lo hi] specifies the mean (lo) % and the standard deviation (hi) of the final distribution. % -% C = GrB.random (A, 'symmetric') creates a symmetric matrix, like +% C = GrB.random (A, 'symmetric', ...) creates a symmetric matrix, like % the built-in C = sprandsym (A), except that the default % distribution is 'uniform'. The input matrix A must be % square. Only tril(A) is used to construct C. % -% C = GrB.random (n, d, 'symmetric') creates an n-by-n symmetric +% C = GrB.random (n, d, 'symmetric', ...) creates an n-by-n symmetric % matrix C, with a uniform distribution of values. To create % a matrix like C = srandsym (n,d) with the built-in MATLAB % sprandym, use C = GrB.random (n, d, 'symmetric', 'normal'). +% Note that the pair of arguments (m, n, ...) do not appear; +% just a single dimension (n, ...). +% +% To construct a Hermitian matrix instead, use 'hermitian' in place of +% 'symmetric'. % % The rc option of the built-in MATLAB sprand and sprandn is not supported. % @@ -55,13 +60,13 @@ % A = sprand (4, 5, 0.5) % 4-by-5 with at most 10 entries % rng ('default') % C = GrB.random (4, 5, 0.5) % same pattern as A -% assert (isequal (spones (A), spones (C))) +% isequal (spones (A), spones (C)) % % C = GrB.random (C) % same pattern but newly random values % % C = GrB.random (2, 4, inf) % 2-by-4 with all 8 entries % C = GrB.random (2, 4, 0.5, 'normal') % like sprandn (2,4,0.5) -% +% % % random 10-by-10 int16 matrix with entries from -3 to 6, % % including explicit zeros, with a uniform distribution % C = GrB.random (10, 10, 0.5, 'range', int16 ([-3 6])) @@ -82,103 +87,14 @@ % histogram (x, 'BinMethod', 'integers') ; % % % large symmetric matrix with normal distribution -% C1 = GrB.random (1e6, 1e-5, 'symmetric', 'normal') +% C = GrB.random (1e6, 1e-5, 'symmetric', 'normal') % [i,j,x] = find (C) ; % histogram (x) % -% See also sprand, sprandn, sprandsym, GrB/sprand, GrB/sprandn, GrB/sprandsym. - -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. - -% defaults -dist = 'uniform' ; -type = 'double' ; -range = [ ] ; -sym_option = 'unsymmetric' ; -firstchar = nargin + 1 ; - -% parse input options -for k = 1:nargin - arg = varargin {k} ; - if (ischar (arg)) - firstchar = min (firstchar, k) ; - switch arg - case { 'uniform', 'normal' } - dist = arg ; - case 'range' - range = varargin {k+1} ; - type = GrB.type (range) ; - case { 'unsymmetric', 'symmetric' } - sym_option = arg ; - otherwise - gb_error ('unknown option') ; - end - end -end - -symmetric = isequal (sym_option, 'symmetric') ; -desc.base = 'zero-based' ; - -% construct the pattern -if (firstchar == 2) - % C = GrB.random (A, ...) ; - A = varargin {1} ; - [m, n] = size (A) ; - if (symmetric && (m ~= n)) - gb_error ('input matrix must be square') ; - end - [I, J] = GrB.extracttuples (A, desc) ; - e = length (I) ; -elseif (firstchar == (4 - symmetric)) - % C = GrB.random (m, n, d, ...) - % C = GrB.random (n, d, ... 'symmetric') - m = varargin {1} ; - if (symmetric) - n = m ; - d = varargin {2} ; - else - n = varargin {2} ; - d = varargin {3} ; - end - if (isinf (d)) - e = m * n ; - I = repmat ((int64 (0) : int64 (m-1)), 1, n) ; - J = repmat ((int64 (0) : int64 (n-1)), m, 1) ; - else - e = round (m * n * d) ; - I = int64 (floor (rand (e, 1) * m)) ; - J = int64 (floor (rand (e, 1) * n)) ; - end -else - gb_error ('invalid usage') ; -end - -% construct the values -if (islogical (range)) - X = true ; -else - if (isequal (dist, 'uniform')) - X = rand (e, 1) ; - else - X = randn (e, 1) ; - end - if (~isempty (range)) - lo = min (double (range)) ; - hi = max (double (range)) ; - if (isinteger (range)) - X = cast (floor ((hi - lo + 1) * X + lo), type) ; - else - X = cast ((hi - lo) * X + lo, type) ; - end - end -end +% See also GrB/sprand, GrB/sprandn, GrB/sprandsym. -% build the matrix -C = GrB.build (I, J, X, m, n, '2nd', desc) ; +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% make it symmetric, if requested -if (symmetric) - C = tril (C) + tril (C, -1)' ; -end +C = GrB (gb_random (varargin {:})) ; diff --git a/GraphBLAS/@GrB/rdivide.m b/GraphBLAS/@GrB/rdivide.m index 79fc41fb82..6738b63646 100644 --- a/GraphBLAS/@GrB/rdivide.m +++ b/GraphBLAS/@GrB/rdivide.m @@ -1,53 +1,54 @@ function C = rdivide (A, B) -%TIMES C = A./B, sparse matrix element-wise division. +%RDIVIDE C = A./B, sparse matrix element-wise division. % C = A./B when B is a matrix results in a dense matrix C, with all % entries present. If A is a matrix and B is a scalar, then C has the % pattern of A, except if B is zero and A is double, single, or complex. -% In that case, since 0/0 is NaN, C is a dense matrix. If the types of A -% and B differ, C has the type of A, and B is typecasted into the type of -% A before computing C=A./B. +% In that case, since 0/0 is NaN, C is a dense matrix. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% -% See also rdivide, GrB.emult, GrB.eadd. +% See also GrB/ldivide, GrB.emult, GrB.eadd. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end -if (isscalar (A)) - if (isscalar (B)) +[am, an, atype] = gbsize (A) ; +[bm, bn, btype] = gbsize (B) ; +a_is_scalar = (am == 1) && (an == 1) ; +b_is_scalar = (bm == 1) && (bn == 1) ; +ctype = gboptype (atype, btype) ; + +if (a_is_scalar) + if (b_is_scalar) % both A and B are scalars + C = GrB (gbemult (A, '/', B)) ; else - % A is a scalar, B is a matrix. A is expanded to full - [m, n] = size (B) ; - % A (1:m,1:n) = A and cast to the type of B - A = GrB.subassign (GrB (m, n, GrB.type (B)), A) ; + % A is a scalar, B is a matrix. Expand B to full with type of C + C = GrB (gbapply2 (A, '/', gbfull (B, ctype))) ; end else - if (isscalar (B)) + if (b_is_scalar) % A is a matrix, B is a scalar - if (gb_get_scalar (B) == 0 && isfloat (A)) + if (gb_scalar (B) == 0 && gb_isfloat (atype)) % 0/0 is Nan, and thus must be computed computed if A is % floating-point. The result is a dense matrix. - [m, n] = size (A) ; - % B (1:m,1:n) = B and cast to the type of A - B = GrB.subassign (GrB (m, n, GrB.type (A)), B) ; + % expand B t a full matrix and cast to the type of A + B = gb_scalar_to_full (am, an, atype, B) ; + C = GrB (gbemult (A, '/', B)) ; else % The scalar B is nonzero so just compute A/B in the pattern % of A. The result is sparse (the pattern of A). - B = GrB.expand (B, A) ; + C = GrB (gbapply2 (A, '/', B)) ; end else % both A and B are matrices. The result is a dense matrix. - if (~GrB.isfull (A)) - A = full (A) ; - end - if (~GrB.isfull (B)) - B = full (B) ; - end + C = GrB (gbemult (gbfull (A, ctype), '/', gbfull (B, ctype))) ; end end -C = GrB.emult (A, '/', B) ; - diff --git a/GraphBLAS/@GrB/real.m b/GraphBLAS/@GrB/real.m index 6f57beef32..554c300ba8 100644 --- a/GraphBLAS/@GrB/real.m +++ b/GraphBLAS/@GrB/real.m @@ -1,13 +1,18 @@ function C = real (G) %REAL complex real part. -% C = real (G) returns the real part of the GraphBLAS matrix G. Since -% all GraphBLAS matrices are currently real, real (G) is just G. Complex -% support will be added in the future. +% C = real (G) returns the real part of G. % -% See also GrB/conj. +% See also GrB/conj, GrB/imag. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = G ; +Q = G.opaque ; + +if (contains (gbtype (Q), 'complex')) + C = GrB (gbapply ('creal', Q)) ; +else + % G is already real + C = G ; +end diff --git a/GraphBLAS/@GrB/reduce.m b/GraphBLAS/@GrB/reduce.m index 6e31e54347..255a03f9e4 100644 --- a/GraphBLAS/@GrB/reduce.m +++ b/GraphBLAS/@GrB/reduce.m @@ -1,43 +1,62 @@ -function Cout = reduce (varargin) +function C = reduce (arg1, arg2, arg3, arg4, arg5) %GRB.REDUCE reduce a matrix to a scalar. % -% Usage: +% c = GrB.reduce (monoid, A) +% c = GrB.reduce (monoid, A, desc) +% c = GrB.reduce (cin, accum, monoid, A) +% c = GrB.reduce (cin, accum, monoid, A, desc) % -% cout = GrB.reduce (monoid, A) -% cout = GrB.reduce (monoid, A, desc) -% cout = GrB.reduce (cin, accum, monoid, A) -% cout = GrB.reduce (cin, accum, monoid, A, desc) +% GrB.reduce reduces a matrix to a scalar, using the given monoid: % -% GrB.reduce reduces a matrix to a scalar, using the given monoid. The -% valid monoids are: '+', '*', 'max', and 'min' for all but the 'logical' -% type, and '|', '&', 'xor', and 'ne' for the 'logical' type. See 'help -% GrB.monoidinfo' for more details. +% Monoids for real non-logical types: '+', '*', 'max', 'min', 'any' +% For logical: '|', '&', 'xor', 'eq', 'any' +% For complex types: '+', '*', 'any' +% For integer types: 'bitor', 'bitand', 'bitxor', 'bitxnor' +% +% See 'help GrB.monoidinfo' for more details on the available monoids. % % The monoid and A arguments are required. All others are optional. The % op is applied to all entries of the matrix A to reduce them to a single % scalar result. % -% accum: an optional binary operator (see 'help GrB.binopinfo' for a -% list). +% accum: an optional binary operator (see 'help GrB.binopinfo'). % % cin: an optional input scalar into which the result can be accumulated -% with cout = accum (cin, result). -% -% All input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. cout is returned as a GraphBLAS scalar, by default; -% see 'help GrB/descriptorinfo' for more options. +% with c = accum (cin, result). % -% See also GrB.vreduce; sum, prod, max, min. +% See also GrB.vreduce, GrB/sum, GrB/prod, GrB/max, GrB/min. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% FUTURE: add complex monoids. +if (isobject (arg1)) + arg1 = arg1.opaque ; +end + +if (isobject (arg2)) + arg2 = arg2.opaque ; +end -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +if (nargin > 2 && isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +switch (nargin) + case 2 + [C, k] = gbreduce (arg1, arg2) ; + case 3 + [C, k] = gbreduce (arg1, arg2, arg3) ; + case 4 + [C, k] = gbreduce (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbreduce (arg1, arg2, arg3, arg4, arg5) ; +end -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - Cout = GrB (gbreduce (args {:})) ; -else - Cout = gbreduce (args {:}) ; +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/repmat.m b/GraphBLAS/@GrB/repmat.m index 95412405d2..411ffda095 100644 --- a/GraphBLAS/@GrB/repmat.m +++ b/GraphBLAS/@GrB/repmat.m @@ -1,19 +1,22 @@ function C = repmat (G, m, n) -%REPMAT Replicate and tile a GraphBLAS matrix. -% C = repmat (G, m, n) % constructs an m-by-n tiling of the GrB matrix A +%REPMAT replicate and tile a matrix. +% C = repmat (G, m, n) % constructs an m-by-n tiling of the matrix G % C = repmat (G, [m n]) % same as C = repmat (A, m, n) -% C = repmat (G, n) % constructs an n-by-n tiling of the GrB matrix G +% C = repmat (G, n) % constructs an n-by-n tiling of the matrix G % -% See also kron, GrB.kronecker. +% See also GrB/kron, GrB.kronecker. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; if (nargin == 3) R = ones (m, n, 'logical') ; else R = ones (m, 'logical') ; end -op = ['2nd.' GrB.type(G)] ; -C = GrB.kronecker (R, op, G) ; +op = ['2nd.' type] ; +C = GrB (gbkronecker (R, op, G)) ; diff --git a/GraphBLAS/@GrB/reshape.m b/GraphBLAS/@GrB/reshape.m index b30151a85e..97225a719d 100644 --- a/GraphBLAS/@GrB/reshape.m +++ b/GraphBLAS/@GrB/reshape.m @@ -1,43 +1,38 @@ -function C = reshape (G, arg1, arg2) -%RESHAPE Reshape a GraphBLAS matrix. +function C = reshape (G, varargin) +%RESHAPE reshape a matrix. % C = reshape (G, m, n) or C = reshape (G, [m n]) returns the m-by-n % matrix whose elements are taken columnwise from G. The matrix G must % have numel (G) == m*n. That is numel (G) == numel (C) must be true. % -% See also numel, squeeze. +% See also GrB/numel, squeeze. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -[mold, nold] = size (G) ; +% FUTURE: this would be faster as a built-in GxB_reshape function. + +if (isobject (G)) + G = G.opaque ; +end + +[mold, nold, ~] = gbsize (G) ; mold = int64 (mold) ; nold = int64 (nold) ; -if (nargin == 2) - if (length (arg1) ~= 2) - gb_error ('reshape (G,s): s must have exactly two elements') ; - end - mnew = int64 (arg1 (1)) ; - nnew = int64 (arg1 (2)) ; -elseif (nargin == 3) - if (~isscalar (arg1) || ~isscalar (arg2)) - gb_error ('reshape (G,m,n): m and n must be scalars') ; - end - mnew = int64 (arg1) ; - nnew = int64 (arg2) ; -end + +[mnew, nnew] = gb_parse_dimensions (varargin {:}) ; +mnew = int64 (mnew) ; +nnew = int64 (nnew) ; + if (mold * nold ~= mnew * nnew) - gb_error ('number of elements must not change') ; -end -if (isempty (G)) - C = GrB (mnew, nnew, GrB.type (G)) ; -else - desc.base = 'zero-based' ; - [iold, jold, x] = GrB.extracttuples (G, desc) ; - % convert i and j from 2D (mold-by-nold) to 1D indices - k = gb_convert_index_2d_to_1d (iold, jold, mold) ; - % convert k from 1D indices to 2D (mnew-by-nnew) - [inew, jnew] = gb_convert_index_1d_to_2d (k, mnew) ; - % rebuild the new matrix - C = GrB.build (inew, jnew, x, mnew, nnew, desc) ; + error ('number of elements must not change') ; end +desc.base = 'zero-based' ; +[iold, jold, x] = gbextracttuples (G, desc) ; +% convert i and j from 2D (mold-by-nold) to 1D indices +k = gb_convert_index_2d_to_1d (iold, jold, mold) ; +% convert k from 1D indices to 2D (mnew-by-nnew) +[inew, jnew] = gb_convert_index_1d_to_2d (k, mnew) ; +% rebuild the new matrix +C = GrB (gbbuild (inew, jnew, x, mnew, nnew, desc)) ; + diff --git a/GraphBLAS/@GrB/round.m b/GraphBLAS/@GrB/round.m index cf60cd104a..f53aba9806 100644 --- a/GraphBLAS/@GrB/round.m +++ b/GraphBLAS/@GrB/round.m @@ -1,20 +1,21 @@ function C = round (G) -%ROUND round entries of a GraphBLAS matrix to the nearest integers -% C = round (G) rounds the entries in the GraphBLAS matrix G to the -% nearest integers. +%ROUND round entries of a matrix to the nearest integers. +% C = round (G) rounds the entries of G to the nearest integers. % -% See also ceil, floor, fix. +% Note: the additional parameters of the built-in MATLAB round function, +% round(x,n) and round (x,n,type), are not supported. +% +% See also GrB/ceil, GrB/floor, GrB/fix. + +% FUTURE: round (x,n) and round (x,n,type) -% FUTURE: this will be much faster as a mexFunction. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +Q = G.opaque ; -if (isfloat (G) && GrB.entries (G) > 0) - [m, n] = size (G) ; - desc.base = 'zero-based' ; - [i, j, x] = GrB.extracttuples (G, desc) ; - C = GrB.build (i, j, round (x), m, n, desc) ; +if (gb_isfloat (gbtype (Q)) && gbnvals (Q) > 0) + C = GrB (gbapply ('round', Q)) ; else C = G ; end diff --git a/GraphBLAS/@GrB/sec.m b/GraphBLAS/@GrB/sec.m new file mode 100644 index 0000000000..e37fe4b4bf --- /dev/null +++ b/GraphBLAS/@GrB/sec.m @@ -0,0 +1,18 @@ +function C = sec (G) +%SEC secant. +% C = sec (G) is the secant of each entry of G. +% Since sec (0) = 1, the result is a full matrix. +% +% See also GrB/asec, GrB/sech, GrB/asech. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gbapply ('minv', gbapply ('cos', gbfull (G, type)))) ; + diff --git a/GraphBLAS/@GrB/sech.m b/GraphBLAS/@GrB/sech.m new file mode 100644 index 0000000000..3bff483c45 --- /dev/null +++ b/GraphBLAS/@GrB/sech.m @@ -0,0 +1,18 @@ +function C = sech (G) +%SECH hyperbolic secant. +% C = sech (G) is the hyperbolic secant of each entry of G. +% Since sech(0) is nonzero, C is a full matrix. +% +% See also GrB/sec, GrB/asec, GrB/asech. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +type = gbtype (G) ; +if (~gb_isfloat (type)) + type = 'double' ; +end + +C = GrB (gbapply ('minv', gbapply ('cosh', gbfull (G, type)))) ; + diff --git a/GraphBLAS/@GrB/select.m b/GraphBLAS/@GrB/select.m index 70a72bcdb3..553f3aa72d 100644 --- a/GraphBLAS/@GrB/select.m +++ b/GraphBLAS/@GrB/select.m @@ -1,23 +1,21 @@ -function Cout = select (varargin) +function C = select (arg1, arg2, arg3, arg4, arg5, arg6, arg7) %GRB.SELECT: select entries from a GraphBLAS sparse matrix. % -% Usage: +% C = GrB.select (selectop, A) +% C = GrB.select (selectop, A, b) +% C = GrB.select (selectop, A, b, desc) % -% Cout = GrB.select (selectop, A) -% Cout = GrB.select (selectop, A, b) -% Cout = GrB.select (selectop, A, b, desc) +% C = GrB.select (Cin, accum, selectop, A) +% C = GrB.select (Cin, accum, selectop, A, b) +% C = GrB.select (Cin, accum, selectop, A, b, desc) % -% Cout = GrB.select (Cin, accum, selectop, A) -% Cout = GrB.select (Cin, accum, selectop, A, b) -% Cout = GrB.select (Cin, accum, selectop, A, b, desc) +% C = GrB.select (Cin, M, selectop, A) +% C = GrB.select (Cin, M, selectop, A, b) +% C = GrB.select (Cin, M, selectop, A, b, desc) % -% Cout = GrB.select (Cin, M, selectop, A) -% Cout = GrB.select (Cin, M, selectop, A, b) -% Cout = GrB.select (Cin, M, selectop, A, b, desc) -% -% Cout = GrB.select (Cin, M, accum, selectop, A) -% Cout = GrB.select (Cin, M, accum, selectop, A, b) -% Cout = GrB.select (Cin, M, accum, selectop, A, b, desc) +% C = GrB.select (Cin, M, accum, selectop, A) +% C = GrB.select (Cin, M, accum, selectop, A, b) +% C = GrB.select (Cin, M, accum, selectop, A, b, desc) % % GrB.select selects a subset of entries from the matrix A, based on % their value or position. For example, L = GrB.select ('tril', A, 0) @@ -51,8 +49,8 @@ % '<' C = A (A < b) % '<=' C = A (A <= b) % -% Note that C = GrB.select ('diag',A,b) does not returns a vector, -% but a diagonal matrix. +% Note that C = GrB.select ('diag',A,b) does not return a vector, +% but a diagonal matrix, instead. % % Many of the operations have equivalent synonyms, as listed above. % @@ -76,23 +74,53 @@ % A is the input matrix. It is transposed on input if desc.in0 = % 'transpose'. % -% The descriptor desc is optional. If not present, all default settings -% are used. Fields not present are treated as their default values. See -% 'help GrB.descriptorinfo' for more details. -% -% All input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. Cout is returned as a GraphBLAS matrix, by default; -% see 'help GrB/descriptorinfo' for more options. +% desc is optional. See 'help GrB.descriptorinfo' for more details. % -% See also tril, triu, diag. +% See also GrB/tril, GrB/triu, GrB/diag. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (arg1)) + arg1 = arg1.opaque ; +end + +if (isobject (arg2)) + arg2 = arg2.opaque ; +end + +if (nargin > 2 && isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +if (nargin > 4 && isobject (arg5)) + arg5 = arg5.opaque ; +end + +if (nargin > 5 && isobject (arg6)) + arg6 = arg6.opaque ; +end -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +switch (nargin) + case 2 + [C, k] = gbselect (arg1, arg2) ; + case 3 + [C, k] = gbselect (arg1, arg2, arg3) ; + case 4 + [C, k] = gbselect (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbselect (arg1, arg2, arg3, arg4, arg5) ; + case 6 + [C, k] = gbselect (arg1, arg2, arg3, arg4, arg5, arg6) ; + case 7 + [C, k] = gbselect (arg1, arg2, arg3, arg4, arg5, arg6, arg7) ; +end -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - Cout = GrB (gbselect (args {:})) ; -else - Cout = gbselect (args {:}) ; +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/selectopinfo.m b/GraphBLAS/@GrB/selectopinfo.m index 87d0daf8f7..04817f0205 100644 --- a/GraphBLAS/@GrB/selectopinfo.m +++ b/GraphBLAS/@GrB/selectopinfo.m @@ -1,7 +1,6 @@ function selectopinfo (op) %GRB.SELECTOPINFO list the details of a GraphBLAS select operator. % -% Usage % GrB.selectopinfo % GrB.selectopinfo (op) % @@ -27,8 +26,8 @@ function selectopinfo (op) % '<' C = A (A < b) % '<=' C = A (A <= b) % -% All select operators are type-generic, so no '.' appears, as they -% do for other operators. +% All select operators are type-generic, so no '.' appears, as they do for +% other operators. % % Example: % @@ -38,8 +37,8 @@ function selectopinfo (op) % See also GrB.binopinfo, GrB.descriptorinfo, GrB.monoidinfo, % GrB.semiringinfo, GrB.unopinfo. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. if (nargin == 0) help GrB.selectopinfo diff --git a/GraphBLAS/@GrB/semiringinfo.m b/GraphBLAS/@GrB/semiringinfo.m index 71cf48a7e0..399660b409 100644 --- a/GraphBLAS/@GrB/semiringinfo.m +++ b/GraphBLAS/@GrB/semiringinfo.m @@ -1,8 +1,6 @@ function semiringinfo (s, type) %GRB.SEMIRINGINFO list the details of a GraphBLAS semiring. % -% Usage -% % GrB.semiringinfo % GrB.semiringinfo (semiring) % GrB.semiringinfo (semiring, type) @@ -16,15 +14,12 @@ function semiringinfo (s, type) % provided, either in the semiring as GrB.semiringinfo ('+.*.double'), or % in the second argument, GrB.semiringinfo ('+.*', 'double'). % -% The add operator must be a valid monoid: plus, times, min, max, and the -% boolean operators or.logical, and.logical, ne.logical, and xor.logical. -% The binary operator z=f(x,y) of a monoid must be associative and -% commutative, with an identity value id such that f(x,id) = f(id,x) = x. -% Furthermore, the types of x, y, and z for the monoid operator f must -% all be the same. Thus, the '<.double' is not a valid monoid operator, -% since its 'logical' output type does not match its 'double' inputs, and -% since it is neither associative nor commutative. Thus, <.*.double is -% not a valid semiring. +% The additive operator must be the binary operator of a valid monoid (see +% 'help GrB.monoidinfo'). The multiplicative operator can be any binary +% operator z=f(x,y) listed by 'help GrB.binopinfo', but the type of z must +% match the operand type of the monoid. The type in the string +% 'add.mult.type' is the type of x for the multiply operator z=f(x,y), and +% the type of its z output defines the type of the monoid. % % Example: % @@ -38,10 +33,8 @@ function semiringinfo (s, type) % See also GrB.binopinfo, GrB.descriptorinfo, GrB.monoidinfo, % GrB.selectopinfo, GrB.unopinfo. -% FUTURE: add complex semirings - -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. if (nargin == 0) help GrB.semiringinfo diff --git a/GraphBLAS/@GrB/sign.m b/GraphBLAS/@GrB/sign.m index a825cb353b..5b4ef5798a 100644 --- a/GraphBLAS/@GrB/sign.m +++ b/GraphBLAS/@GrB/sign.m @@ -1,14 +1,22 @@ function C = sign (G) -%SIGN Signum function. -% C = sign (G) computes the signum function for each entry in the -% GraphBLAS matrix G. For each element of G, sign(G) returns 1 if the -% element is greater than zero, 0 if it equals zero, and -1 if it is less -% than zero. The output C is a GraphBLAS matrix. +%SIGN signum function. +% C = sign (G) is the signum function for each entry of G. For real +% values, sign(x) is 1 if x > 0, zero if x is zero, and -1 if x < 0. +% For the complex case, sign(x) = x ./ abs (x). % -% See also abs. +% See also GrB/abs. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = spones (GrB.select (G, '>0')) - spones (GrB.select (G, '<0')) ; +Q = G.opaque ; +type = gbtype (Q) ; + +if (isequal (type, 'logical')) + C = G ; +elseif (~gb_isfloat (type)) + C = GrB (gbnew (gbapply ('signum.single', Q), type)) ; +else + C = GrB (gbapply ('signum', Q)) ; +end diff --git a/GraphBLAS/@GrB/sin.m b/GraphBLAS/@GrB/sin.m new file mode 100644 index 0000000000..f936bfe696 --- /dev/null +++ b/GraphBLAS/@GrB/sin.m @@ -0,0 +1,18 @@ +function C = sin (G) +%SIN sine. +% C = sin (G) is the sine of each entry of G. +% +% See also GrB/asin, GrB/sinh, GrB/asinh. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +if (~gb_isfloat (gbtype (G))) + op = 'sin.double' ; +else + op = 'sin' ; +end + +C = GrB (gbapply (op, G)) ; + diff --git a/GraphBLAS/@GrB/single.m b/GraphBLAS/@GrB/single.m index 8e2f4b4f14..a9b0aa3dac 100644 --- a/GraphBLAS/@GrB/single.m +++ b/GraphBLAS/@GrB/single.m @@ -2,16 +2,23 @@ %SINGLE cast a GraphBLAS matrix to MATLAB full single matrix. % C = single (G) typecasts the GrB matrix G to a MATLAB full single % matrix. The result C is full since MATLAB does not support sparse -% single matrices. +% single matrices. C is real if G is real, and complex if G is complex. % % To typecast the matrix G to a GraphBLAS sparse single matrix instead, -% use C = GrB (G, 'single'). +% use C = GrB (G, 'single'). To typecast to a sparse single complex +% matrix, use G = GrB (G, 'single complex'). % -% See also GrB, double, complex, logical, int8, int16, int32, int64, -% uint8, uint16, uint32, and uint64. +% See also GrB, GrB/double, GrB/complex, GrB/logical, GrB/int8, GrB/int16, +% GrB/int32, GrB/int64, GrB/uint8, GrB/uint16, GrB/uint32, GrB/uint64. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = gbfull (G.opaque, 'single') ; +G = G.opaque ; +desc.kind = 'full' ; +if (contains (gbtype (G), 'complex')) + C = gbfull (G, 'single complex', complex (single (0)), desc) ; +else + C = gbfull (G, 'single', single (0), desc) ; +end diff --git a/GraphBLAS/@GrB/sinh.m b/GraphBLAS/@GrB/sinh.m new file mode 100644 index 0000000000..626a610411 --- /dev/null +++ b/GraphBLAS/@GrB/sinh.m @@ -0,0 +1,18 @@ +function C = sinh (G) +%SINH hyperbolic sine. +% C = sinh (G) is the hyperbolic sine of each entry of G. +% +% See also GrB/sin, GrB/asin, GrB/asinh. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +if (~gb_isfloat (gbtype (G))) + op = 'sinh.double' ; +else + op = 'sinh' ; +end + +C = GrB (gbapply (op, G)) ; + diff --git a/GraphBLAS/@GrB/size.m b/GraphBLAS/@GrB/size.m index 0fea3ad028..affaf490b2 100644 --- a/GraphBLAS/@GrB/size.m +++ b/GraphBLAS/@GrB/size.m @@ -1,19 +1,20 @@ -function [arg1, n] = size (G, dim) -%SIZE the dimensions of a GraphBLAS matrix. -% [m n] = size (G) is the size of an m-by-n GraphBLAS sparse matrix. +function [m, n] = size (G, dim) +%SIZE the dimensions of a matrix. +% [m n] = size (G) is the size of an m-by-n sparse matrix. % If any dimension exceeds flintmax (2^53), m and n are returned as int64. % % See also GrB/length, GrB/numel. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -if (nargout <= 1) - arg1 = gbsize (G.opaque) ; - if (nargin == 2) - arg1 = arg1 (dim) ; - end -else - [arg1, n] = gbsize (G.opaque) ; +G = G.opaque ; +[m, n] = gbsize (G) ; + +if (nargin == 2) + s = [m n] ; + m = s (dim) ; +elseif (nargout == 1) + m = [m n] ; end diff --git a/GraphBLAS/@GrB/sparse.m b/GraphBLAS/@GrB/sparse.m index 01c189bcd4..13777fe137 100644 --- a/GraphBLAS/@GrB/sparse.m +++ b/GraphBLAS/@GrB/sparse.m @@ -3,10 +3,10 @@ % Since G is already sparse, C = sparse (G) simply makes a copy of G. % Explicit zeros are not removed. To remove them use C = GrB.prune(G). % -% See also GrB/issparse, GrB/full, GrB.type, GrB. +% See also GrB/issparse, GrB/full, GrB.type, GrB/prune, GrB. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. C = G ; diff --git a/GraphBLAS/@GrB/speye.m b/GraphBLAS/@GrB/speye.m index bf767b1b0c..6b70511730 100644 --- a/GraphBLAS/@GrB/speye.m +++ b/GraphBLAS/@GrB/speye.m @@ -1,12 +1,12 @@ function C = speye (varargin) -%GRB.SPEYE Sparse identity matrix, of any type supported by GraphBLAS. +%GRB.SPEYE sparse identity matrix. % C = GrB.speye (...) is identical to GrB.eye; see 'help GrB.eye' for % details. % % See also GrB.eye. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB.eye (varargin {:}) ; +C = GrB (gb_speye ('speye', varargin {:})) ; diff --git a/GraphBLAS/@GrB/spfun.m b/GraphBLAS/@GrB/spfun.m index c451918175..261bf145d6 100644 --- a/GraphBLAS/@GrB/spfun.m +++ b/GraphBLAS/@GrB/spfun.m @@ -1,18 +1,63 @@ function C = spfun (fun, G) -%SPFUN Apply function to the entries of a GraphBLAS matrix. +%SPFUN apply function to the entries of a matrix. % C = spfun (fun, G) evaluates the function fun on the entries of G. % -% See also GrB.apply. +% If fun is a string, it can be any GraphBLAS unary operator (type +% 'help GrB.unopinfo' for a list). The string can take the form of +% just the name of the operator ('sqrt', for example), or it can have +% the type appended, as ('sqrt.double', 'sqrt.double complex', etc). +% The latter produces a complex result. sqrt.double (x) returns NaN if +% x is negative. By default, the function type is determined from the +% type of the input matrix G. GrB/spfun does not attempt to select the +% operator based on the values, in contract with GrB/sqrt, for example. +% For a list of types, see 'help GrB.type'. +% +% If the string fun is not a GraphBLAS operator, or if fun is a MATLAB +% function handle, then feval(fun,x) is used instead. +% +% The function is not applied to entries not present in G. Since a +% GraphBLAS matrix can include explicit zeros, the function fun is +% applied to them as well. Use GrB.prune to remove them, if necessary. +% +% Example: +% +% A = sprand (4, 4, 0.5) +% G = GrB (A) ; +% Z = spfun ('exp', A) +% Y = spfun ('exp', G) +% C = exp (G) +% +% % sqrt.double (-1) is nan: +% z = spfun ('sqrt', GrB (-1)) +% % but sqrt.complex (-1) is 1i: +% z = spfun ('sqrt', GrB (-1, 'complex')) +% z = spfun ('sqrt.complex', GrB (-1)) +% % the overloaded GrB/sqrt function checks its inputs: +% z = sqrt (GrB (2)) +% z = sqrt (GrB (-1)) +% +% See also GrB.apply, GrB.unopinfo. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% FUTURE: this would be much faster as a mexFunction, but calling feval -% from inside a mexFunction would not be trivial (perhaps not possible). +if (isobject (G)) + G = G.opaque ; +end -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +if (ischar (fun)) + try + C = GrB (gbapply (fun, G)) ; + return ; + catch me %#ok + % gbapply failed; fall through to feval below + end +end -[m, n] = size (G) ; +% 'fun' is not a string, or not a built-in GraphBLAS operator +[m, n] = gbsize (G) ; desc.base = 'zero-based' ; -[i, j, x] = GrB.extracttuples (G, desc) ; +[i, j, x] = gbextracttuples (G, desc) ; x = feval (fun, x) ; -C = GrB.build (i, j, x, m, n, '1st', GrB.type (x), desc) ; +C = GrB.build (i, j, x, m, n, '1st', desc) ; diff --git a/GraphBLAS/@GrB/spones.m b/GraphBLAS/@GrB/spones.m index 09b9f9b286..c5692ea322 100644 --- a/GraphBLAS/@GrB/spones.m +++ b/GraphBLAS/@GrB/spones.m @@ -1,5 +1,5 @@ function C = spones (G, type) -%SPONES return pattern of GraphBLAS matrix. +%SPONES return pattern of a sparse matrix. % C = spones (G) returns a matrix C with the same pattern as G, but with % all entries set to 1. The behavior of spones (G) for a GrB matrix % differs from spones (A) for a MATLAB matrix A. An explicit entry @@ -7,22 +7,23 @@ % C(i,j)=1. Explicit zero entries never appear in a MATLAB sparse % matrix. % -% C = spones (G) returns C as the same type as G. +% C = spones (G) returns C as the same type as G if G is real. +% If G is complex, C has the underlying real type of G ('single' if +% G is 'single complex', or 'double' if G is 'double complex'). +% % C = spones (G,type) returns C in the requested type ('double', % 'single', 'int8', ...). For example, use C = spones (G, 'logical') to % return the pattern of G as a sparse logical matrix. % -% See also spfun, GrB.apply. +% See also GrB/spfun, GrB.apply. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. +G = G.opaque ; if (nargin == 1) - C = GrB.apply ('1', G) ; + C = GrB (gb_spones (G)) ; else - if (~ischar (type)) - gb_error ('type must be a string') ; - end - C = GrB.apply (['1.' type], G) ; + C = GrB (gb_spones (G, type)) ; end diff --git a/GraphBLAS/@GrB/sprand.m b/GraphBLAS/@GrB/sprand.m index 5450826617..85d1bce15e 100644 --- a/GraphBLAS/@GrB/sprand.m +++ b/GraphBLAS/@GrB/sprand.m @@ -1,13 +1,36 @@ -function C = sprand (G) -%SPRAND sparse uniformly distributed GraphBLAS random matrix. -% C = sprand (G) has the same pattern as A, but uniformly -% distributed random entries. If the same random seed is used, -% and if G and A have the same pattern, sprand (G) and the MATLAB -% sprand (A) produce the same result. +function C = sprand (arg1, arg2, arg3) +%SPRAND sparse uniformly distributed random matrix. +% C = sprand (A) is a matrix with the same pattern as A, but with +% uniformly distributed random entries. This usage is identical to +% C = GrB.random (A). % +% C = sprand (m,n,d) is a random m-by-n matrix with about m*n*d uniformly +% distributed values. If d == inf, C is a full matrix. To use this +% function instead of the built-in sprand, use C = sprand (m,n,GrB(d)), +% for example, or C = GrB.random (m,n,d). +% +% For additional options, see GrB.random. +% The rc parameter for C = sprand (m,n,d,rc) is not supported. % The entries in C will greater than zero and less than one. +% C is returned as a double GraphBLAS matrix. % -% See also sprand, sprandn, sprandsym, GrB.random. +% See also GrB/sprandn, GrB/sprandsym, GrB.random. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB.random (G) ; +if (nargin == 1) + % C = sprand (G) + G = arg1.opaque ; + C = GrB (gb_random (G)) ; +elseif (nargin == 3) + % C = sprand (m, n, d) + m = gb_get_scalar (arg1) ; + n = gb_get_scalar (arg2) ; + d = gb_get_scalar (arg3) ; + C = GrB (gb_random (m, n, d)) ; +else + % the 'rc' input option is not supported + error ('usage: sprand(A) or sprand(m,n,d)') ; +end diff --git a/GraphBLAS/@GrB/sprandn.m b/GraphBLAS/@GrB/sprandn.m index 855f073d48..eaa5792f39 100644 --- a/GraphBLAS/@GrB/sprandn.m +++ b/GraphBLAS/@GrB/sprandn.m @@ -1,11 +1,34 @@ -function C = sprandn (G) -%SPRANDN sparse uniformly distributed GraphBLAS random matrix. -% C = sprandn (G) has the same pattern as A, but uniformly -% distributed random entries. If the same random seed is used, -% and if G and A have the same pattern, sprand (G) and the MATLAB -% sprand (A) produce the same result. +function C = sprandn (arg1, arg2, arg3) +%SPRANDN sparse normally distributed random matrix. +% C = sprandn (A) is a matrix with the same pattern as A, +% but with normally distributed random entries. % -% See also sprand, sprandn, sprandsym, GrB.random. +% C = sprandn (m,n,d) is a random m-by-n matrix with about m*n*d normally +% distributed values. If d == inf, C is a full matrix. To use this +% function instead of the built-in sprandn, use C = sprandn (m,n,GrB(d)), +% for example, or C = GrB.random (m,n,d,'normal'). +% +% For additional options, see GrB.random. +% The rc parameter for C = sprandn (m,n,d,rc) is not supported. +% C is returned as a double GraphBLAS matrix. +% +% See also GrB/sprandn, GrB/sprandsym, GrB.random. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB.random (G, 'normal') ; +if (nargin == 1) + % C = sprandn (G) + G = arg1.opaque ; + C = GrB (gb_random (G, 'normal')) ; +elseif (nargin == 3) + % C = sprandn (m, n, d) + m = gb_get_scalar (arg1) ; + n = gb_get_scalar (arg2) ; + d = gb_get_scalar (arg3) ; + C = GrB (gb_random (m, n, d, 'normal')) ; +else + % the 'rc' input option is not supported + error ('usage: sprandn(A) or sprandn(m,n,d)') ; +end diff --git a/GraphBLAS/@GrB/sprandsym.m b/GraphBLAS/@GrB/sprandsym.m index f233c3d022..2b13c5c75f 100644 --- a/GraphBLAS/@GrB/sprandsym.m +++ b/GraphBLAS/@GrB/sprandsym.m @@ -1,16 +1,18 @@ -function C = sprandsym (G, varargin) -%SPRANDSYM random symmetric GraphBLAS matrix -% C = sprandsym (G) is a symmetric random GraphBLAS matrix. Its -% lower triangle and diagonal have the same pattern as tril (G). -% The values of C have a normal distribution. G must be square. -% -% All optional parameters of GrB.random may be used: -% -% C = sprandsym (G, 'uniform') uses a uniform distribution instead. -% -% C = sprandsym (G, 'range', [lo hi]) modifies the range of the -% distribution. See GrB.random for more details. The class of -% [lo hi] determines the class of C ('double', 'single', ...). +function C = sprandsym (arg1, arg2) +%SPRANDSYM random symmetric matrix. +% C = sprandsym (A) is a symmetric random matrix. Its lower triangle and +% diagonal have the same pattern as tril (A). The values of C have a +% normal distribution. A must be square. This usage is the same as +% C = GrB.random (A, 'symmetric', 'normal'). +% +% C = sprandsym (n,d) is an n-by-n symmetric random matrix with about n*n*d +% entries, with a normal distribution. If d == inf, C is full. To use +% this function instead of the built-in MATLAB sprandsym, use +% C = sprandsym (n,GrB(d)), or C = GrB.random (n,d,'symmetric','normal'). +% +% For additional options, see GrB.random. +% The C = sprandsym (n,d,rc) syntax is not supported. +% C is returned as a double GraphBLAS matrix. % % Example: % @@ -18,35 +20,20 @@ % G = GrB (A) ; % C0 = sprandsym (A) ; % the built-in sprandsym % C1 = sprandsym (G) ; % GrB/sprandsym -% C2 = sprandsym (G, 'normal') ; % same as sprandsym(G) -% C3 = sprandsym (G, 'uniform') ; % uniform distribution -% -% C = sprandsym (G, 'range', int16 ([-3 6])) ; -% [i,j,x] = find (C) ; -% histogram (x, 'BinMethod', 'integers') ; % -% C = sprandsym (G, 'uniform', 'range', int16 ([-3 6])) ; -% [i,j,x] = find (C) ; -% histogram (x, 'BinMethod', 'integers') ; -% -% See also sprand, sprandn, GrB/sprand, GrB.random. +% See also GrB/sprand, GrB/sprandn, GrB.random. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -% make the default 'normal' instead of 'uniform' -have_dist = false ; -for k = 1:nargin-1 - arg = varargin {k} ; - if (ischar (arg)) - if (isequal (arg, 'uniform') || isequal (arg, 'normal')) - have_dist = true ; - end - end -end -if (~have_dist) - varargin {end+1} = 'normal' ; +if (nargin == 1) + % C = sprandsym (G) + G = arg1.opaque ; + C = GrB (gb_random (G, 'symmetric', 'normal')) ; +else + % C = sprandsym (n, d) + n = gb_get_scalar (arg1) ; + d = gb_get_scalar (arg2) ; + C = GrB (gb_random (n, d, 'symmetric', 'normal')) ; end -C = GrB.random (G, 'symmetric', varargin {:}) ; - diff --git a/GraphBLAS/@GrB/sprintf.m b/GraphBLAS/@GrB/sprintf.m index a1b06e73cc..c54e1a2e99 100644 --- a/GraphBLAS/@GrB/sprintf.m +++ b/GraphBLAS/@GrB/sprintf.m @@ -1,13 +1,13 @@ function s = sprintf (varargin) -%SPRINTF Write formatted data to a string. +%SPRINTF write formatted data to a string. % The GraphBLAS sprintf function is identical to the built-in MATLAB % function; this overloaded method simply typecasts any GraphBLAS % matrices to MATLAB matrices first, and then calls the builtin sprintf. % % See also fprintf, sprintf, GrB/fprintf. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. s = gb_printf_helper ('sprintf', varargin {:}) ; diff --git a/GraphBLAS/@GrB/sqrt.m b/GraphBLAS/@GrB/sqrt.m index 6e4fd5255c..3998e05106 100644 --- a/GraphBLAS/@GrB/sqrt.m +++ b/GraphBLAS/@GrB/sqrt.m @@ -1,13 +1,12 @@ function C = sqrt (G) -%SQRT Square root. -% C = sqrt (G) is the square root of the elements of the GraphBLAS matrix -% G. Complex matrices are not yet supported, and thus currently all -% entries in G must be nonnegative. +%SQRT square root. +% C = sqrt (G) is the square root of the entries of G. % -% See also GrB.apply. +% See also GrB.apply, GrB/hypot. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = G.^(.5) ; +G = G.opaque ; +C = GrB (gb_to_real_if_imag_zero (gb_trig ('sqrt', G))) ; diff --git a/GraphBLAS/@GrB/subassign.m b/GraphBLAS/@GrB/subassign.m index 5abc53d149..d6b7e3042b 100644 --- a/GraphBLAS/@GrB/subassign.m +++ b/GraphBLAS/@GrB/subassign.m @@ -1,20 +1,12 @@ -function Cout = subassign (varargin) +function C = subassign (arg1, arg2, arg3, arg4, arg5, arg6, arg7) %GRB.SUBASSIGN: assign a submatrix into a matrix. % -% GrB.subassign is an interface to GxB_Matrix_subassign and -% GxB_Matrix_subassign_[TYPE], computing the GraphBLAS expression: -% -% C(I,J)<#M,replace> = accum (C(I,J), A) or accum(C(I,J), A') -% -% where A can be a matrix or a scalar. -% -% Usage: -% -% Cout = GrB.subassign (Cin, M, accum, A, I, J, desc) +% C = GrB.subassign (Cin, M, accum, A, I, J, desc) % % Cin and A are required parameters. All others are optional. % The arguments are parsed according to their type. Arguments -% with different types can appear in any order. +% with different types can appear in any order: +% % Cin, M, A: 2 or 3 GraphBLAS or MATLAB sparse/full matrices. % The first three matrix inputs are Cin, M, and A. % If 2 matrix inputs are present, they are Cin and A. @@ -23,7 +15,7 @@ % with one cell input, I is present and J = { }. % with two cell inputs, I is the first cell input and J % is the second cell input. -% desc: an optional struct. +% desc: an optional struct (must appear as the last argument) % % GrB.subassign is identical to GrB.assign, with two key differences: % @@ -50,15 +42,51 @@ % % Refer to GrB.assign for a description of the other input/outputs. % -% See also GrB.assign, subsasgn. +% See also GrB.assign, GrB/subsasgn. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (arg1)) + arg1 = arg1.opaque ; +end + +if (isobject (arg2)) + arg2 = arg2.opaque ; +end -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +if (nargin > 2 && isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +if (nargin > 4 && isobject (arg5)) + arg5 = arg5.opaque ; +end + +if (nargin > 5 && isobject (arg6)) + arg6 = arg6.opaque ; +end + +switch (nargin) + case 2 + [C, k] = gbsubassign (arg1, arg2) ; + case 3 + [C, k] = gbsubassign (arg1, arg2, arg3) ; + case 4 + [C, k] = gbsubassign (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbsubassign (arg1, arg2, arg3, arg4, arg5) ; + case 6 + [C, k] = gbsubassign (arg1, arg2, arg3, arg4, arg5, arg6) ; + case 7 + [C, k] = gbsubassign (arg1, arg2, arg3, arg4, arg5, arg6, arg7) ; +end -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - Cout = GrB (gbsubassign (args {:})) ; -else - Cout = gbsubassign (args {:}) ; +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/subsasgn.m b/GraphBLAS/@GrB/subsasgn.m index 859eac276f..8c8c758db6 100644 --- a/GraphBLAS/@GrB/subsasgn.m +++ b/GraphBLAS/@GrB/subsasgn.m @@ -1,5 +1,5 @@ function C = subsasgn (C, S, A) -%SUBSASGN C(I,J) = A or C(I) = A; assign submatrix into a GraphBLAS matrix +%SUBSASGN C(I,J) = A or C(I) = A; assign submatrix. % C(I,J) = A assigns A into the C(I,J) submatrix of the GraphBLAS matrix % C. A must be either a matrix of size length(I)-by-length(J), or a % scalar. Note that C(I,J) = 0 differs from C(I,J) = sparse (0). The @@ -16,72 +16,80 @@ % indexing, where C and M have the same size, and x(:) is either a vector % of length nnz (M), or a scalar. % -% Note that C (M) = A (M), where the same logical matrix M is used on -% both the sides of the assignment, is identical to C = GrB.subassign (C, -% M, A). If C and A (or M) are GraphBLAS matrices, C (M) = A (M) uses -% GraphBLAS via operator overloading. The statement C (M) = A (M) takes -% about twice the time as C = GrB.subassign (C, M, A), so the latter is -% preferred for best performance. However, both methods in GraphBLAS are -% many thousands of times faster than C (M) = A (M) using purely MATLAB -% sparse matrices C, M, and A, when the matrices are large. So either -% method works fine, relatively speaking. +% C (M) = A (M), where the logical matrix M is used on both the sides of +% the assignment, is the same as C = GrB.subassign (C, M, A). If C and A +% (or M) are GraphBLAS matrices, C (M) = A (M) uses GraphBLAS via operator +% overloading. The statement C (M) = A (M) takes about twice the time as +% C = GrB.subassign (C, M, A), so the latter is preferred for best +% performance. However, both methods in GraphBLAS are many thousands of +% times faster than C (M) = A (M) using purely MATLAB sparse matrices C, M, +% and A, when the matrices are large. % % If I or J are very large colon notation expressions, then C(I,J)=A is % not possible, because MATLAB creates I and J as explicit lists first. % See GrB.subassign instead. See also the example with 'help GrB.extract'. % -% See also subsref, GrB.assign, GrB.subassign. +% Unlike the MATLAB C(I,J)=A, the GraphBLAS assignment does not change +% the size of C. +% +% See also GrB/subsref, GrB/subsindex, GrB.assign, GrB.subassign. -% FUTURE: add linear indexing, and allow the matrix to grow in size. +% FUTURE: add linear indexing, and allow the matrix to grow/shrink in size. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. if (~isequal (S.type, '()')) - error ('GrB:unsupported', 'index type %s not supported', S.type) ; + error ('index type %s not supported', S.type) ; +end + +if (isobject (C)) + C = C.opaque ; +end + +if (isobject (A)) + A = A.opaque ; end ndims = length (S.subs) ; + if (ndims == 1) - if (isequal (GrB.type (S.subs {1}), 'logical')) + + % C (M) = A if M is logical, or C (I) = A otherwise + S = S.subs {1} ; + if (isobject (S)) + S = S.opaque ; + end + if (isequal (gbtype (S), 'logical')) % C (M) = A for logical assignment - M = S.subs {1} ; - % the 'all' syntax requires MATLAB R2019a - % if (any (M, 'all')) - if (isscalar (A)) - % C (M) = scalar - C = GrB.subassign (C, M, A) ; - else - % C (M) = A where A is a vector - if (isa (M, 'GrB')) - M = M.opaque ; - end - if (size (A, 2) ~= 1) - % make sure A is a column vector of size mnz-by-1 - A = A (:) ; - end - if (isa (A, 'GrB')) - A = A.opaque ; - end - if (isa (C, 'GrB')) - C = C.opaque ; - end - C = GrB (gblogassign (C, M, A)) ; - end - % else - % % M is empty, so C does not change - % end + [am, an] = gbsize (A) ; + if (am == 1 && an == 1) + % C (M) = scalar + C = GrB (gbsubassign (C, S, A)) ; + else + % C (M) = A where A is a vector + C = GrB (gblogassign (C, S, A)) ; + end else - % C (I) = A where C is a vector - I = gb_get_index (S.subs (1)) ; - C = GrB.subassign (C, I, A) ; + % C (I) = A + [cm, cn] = gbsize (C) ; + if (cm == 1 || cn == 1) + % C (I) = A for a vector or scalar C + C = GrB (gbsubassign (C, gb_index (S), A)) ; + else + % C (I) = A for a matrix C + error ('Linear indexing not yet supported') ; + end end + elseif (ndims == 2) + % C(I,J) = A where A is length(I)-by-length(J), or a scalar - I = gb_get_index (S.subs (1)) ; - J = gb_get_index (S.subs (2)) ; - C = GrB.subassign (C, I, J, A) ; + C = GrB (gbsubassign (C, gb_index (S.subs {1}), gb_index (S.subs {2}), A)) ; + else - error ('GrB:unsupported', '%dD indexing not supported', ndims) ; + + error ('%dD indexing not yet supported', ndims) ; + end diff --git a/GraphBLAS/@GrB/subsindex.m b/GraphBLAS/@GrB/subsindex.m new file mode 100644 index 0000000000..f02b5052d2 --- /dev/null +++ b/GraphBLAS/@GrB/subsindex.m @@ -0,0 +1,57 @@ +function I = subsindex (G) +%SUBSINDEX subscript index from a GraphBLAS matrix. +% I = subsindex (G) is an overloaded method used when the GraphBLAS +% matrix G is used to index into a non-GraphBLAS matrix A, for A(G). +% +% See also GrB/subsref, GrB/subsasgn. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +% On input, G must contain integers in the range 1 to prod (size (A))-1. +% The dimensions of A are not provided to subsindex. + +G = G.opaque ; + +% As an extension to the MATLAB expression A(G), prune zeros and negative +% values first. The MATLAB expression A(G) becomes A (G (find (G > 0))). +G = gbselect ('>0', G) ; + +[m, n, type] = gbsize (G) ; +if (isinteger (m)) + % G is so huge that gbsize returns m and n as int64. This means + % that m or n (or both) are bigger than flintmax, so G cannot be full. + G_is_full = false ; +else + G_is_full = (m*n == gbnvals (G)) ; +end + +if (isequal (type, 'double') || isequal (type, 'single')) + % double or single: convert to int64 + I = gbextractvalues (G) ; + if (~isequal (I, round (I))) + error ('array indices must be integers') ; + end + I = int64 (I) ; +elseif (contains (type, 'int')) + % any integer: just extract the values + I = gbextractvalues (G) ; +else + % logical or complex + error ('array indices must be integers') ; +end + +% I must contain entries in range 0 to prod (size (A)) - 1, +% so subtract the offset +I = I - 1 ; + +% reshape I as needed +if (m == 1) + % I should be a row vector instead + I = I' ; +elseif (n > 1 && G_is_full) + % I is should be an m-by-n matrix, so reshape it. But I cannot be + % reshaped to m-by-n if G is sparse, so leave it as a column vector. + I = reshape (I, m, n) ; +end + diff --git a/GraphBLAS/@GrB/subsref.m b/GraphBLAS/@GrB/subsref.m index 7264c53ad5..72c3f6aa66 100644 --- a/GraphBLAS/@GrB/subsref.m +++ b/GraphBLAS/@GrB/subsref.m @@ -1,5 +1,5 @@ function C = subsref (A, S) -%SUBSREF C = A(I,J) or C = A(I); extract submatrix of a GraphBLAS matrix. +%SUBSREF C = A(I,J) or C = A(I); extract submatrix. % C = A(I,J) extracts the A(I,J) submatrix of the GraphBLAS matrix A. % With a single index, C = A(I) extracts a subvector C of a vector A. % Linear indexing of a matrix is not yet supported. @@ -26,57 +26,70 @@ % H (I,I) = M % J = {1, 1e13} ; % represents 1:1e13 colon notation % C = H (J, J) % this is very fast -% E = H (1:1e13, 1:1e13) % but this is not possible +% E = H (1:1e13, 1:1e13) % but this is not possible % -% See also subsasgn, GrB.subassign, GrB.assign, GrB.extract. +% See also GrB/subsasgn, GrB/subsindex, GrB.subassign, GrB.assign, +% GrB.extract. % FUTURE: add linear indexing. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end +[m, n] = gbsize (A) ; if (length (S) > 1) - error ('GrB:unsupported', 'nested indexing not supported') ; + error ('nested indexing not supported') ; end if (~isequal (S.type, '()')) - error ('GrB:unsupported', 'index type %s not supported', S.type) ; + error ('index type %s not supported', S.type) ; end ndims = length (S.subs) ; if (ndims == 1) - if (isequal (GrB.type (S.subs {1}), 'logical')) - % C = A (M) for a logical indexing - M = S.subs {1} ; - if (isa (M, 'GrB')) - M = M.opaque ; - end - if (isa (A, 'GrB')) - A = A.opaque ; - end - C = GrB (gblogextract (A, M)) ; + + % C = A(M) if M is logical, or C=A(I) otherwise + S = S.subs {1} ; + if (isobject (S)) + S = S.opaque ; + end + if (isequal (gbtype (S), 'logical')) + % C = A (M) for logical indexing + C = GrB (gblogextract (A, S)) ; else - % C = A (I) for a vector A - if (~isvector (A)) - error ('GrB:unsupported', 'Linear indexing not supported') ; - end - [I, whole_vector] = gb_get_index (S.subs (1)) ; - if (size (A, 1) > 1) - C = GrB.extract (A, I, { }) ; + % C = A (I) + if (m == 1 || n == 1) + % C = A (I) for a vector A + [I, whole] = gb_index (S) ; + if (m > 1) + C = gbextract (A, I, { }) ; + else + C = gbextract (A, { }, I) ; + end + [cm, ~] = gbsize (C) ; + if (whole && cm == 1) + C = gbtrans (C) ; + end + C = GrB (C) ; else - C = GrB.extract (A, { }, I) ; - end - if (whole_vector && size (C,1) == 1) - C = C.' ; + % C = A (I) for a matrix A + error ('Linear indexing not yet supported') ; end end + elseif (ndims == 2) + % C = A (I,J) - I = gb_get_index (S.subs (1)) ; - J = gb_get_index (S.subs (2)) ; - C = GrB.extract (A, I, J) ; + C = GrB (gbextract (A, gb_index (S.subs {1}), gb_index (S.subs {2}))) ; + else - error ('GrB:unsupported', '%dD indexing not supported', ndims) ; + + error ('%dD indexing not yet supported', ndims) ; + end diff --git a/GraphBLAS/@GrB/sum.m b/GraphBLAS/@GrB/sum.m index 0db0523522..bf06046db9 100644 --- a/GraphBLAS/@GrB/sum.m +++ b/GraphBLAS/@GrB/sum.m @@ -1,9 +1,8 @@ function C = sum (G, option) -%SUM Sum of elements. -% C = sum (G), where G is an m-by-n GraphBLAS matrix, computes a 1-by-n -% row vector C where C(j) is the sum of all entries in G(:,j). If G is a -% row or column vector, then sum (G) is a scalar sum of all the entries -% in the vector. +%SUM sum of elements. +% C = sum (G), where G is an m-by-n matrix, computes a 1-by-n row vector C +% where C(j) is the sum of all entries in G(:,j). If G is a row or column +% vector, then sum (G) is a scalar sum of all the entries in the vector. % % C = sum (G,'all') sums all elements of G to a single scalar. % @@ -19,40 +18,22 @@ % GraphBLAS sum (G,...) uses only a type of 'native', and a nanflag of % 'includenan'. See 'help sum' for more details. % -% See also GrB/prod, GrB/max, GrB/min. +% See also GrB/any, GrB/prod, GrB/max, GrB/min. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -if (isequal (GrB.type (G), 'logical')) +G = G.opaque ; + +if (isequal (gbtype (G), 'logical')) op = '+.int64' ; else op = '+' ; end -desc = struct ('in0', 'transpose') ; if (nargin == 1) - % C = sum (G); check if G is a row vector - if (isvector (G)) - % C = sum (G) for a vector G results in a scalar C - C = GrB.reduce (op, G) ; - else - % C = sum (G) reduces each column to a scalar, - % giving a 1-by-n row vector. - C = GrB.vreduce (op, G, desc)' ; - end -elseif (isequal (option, 'all')) - % C = sum (G, 'all'), reducing all entries to a scalar - C = GrB.reduce (op, G) ; -elseif (isequal (option, 1)) - % C = sum (G,1) reduces each column to a scalar, - % giving a 1-by-n row vector. - C = GrB.vreduce (op, G, desc)' ; -elseif (isequal (option, 2)) - % C = sum (G,2) reduces each row to a scalar, - % giving an m-by-1 column vector. - C = GrB.vreduce (op, G) ; + C = GrB (gb_sum (op, G)) ; else - gb_error ('unknown option') ; + C = GrB (gb_sum (op, G, option)) ; end diff --git a/GraphBLAS/@GrB/symamd.m b/GraphBLAS/@GrB/symamd.m index 75b4cc2e7a..b2545f43d6 100644 --- a/GraphBLAS/@GrB/symamd.m +++ b/GraphBLAS/@GrB/symamd.m @@ -1,11 +1,11 @@ function [p, varargout] = symamd (G, varargin) -%SYMAMD approximate minimum degree ordering of a GraphBLAS matrix. +%SYMAMD approximate minimum degree ordering. % See 'help symamd' for details. % -% See also symamd, GrB/amd, GrB/colamd, GrB/symrcm. +% See also GrB/amd, GrB/colamd, GrB/symrcm. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. [p, varargout{1:nargout-1}] = symamd (double (G), varargin {:}) ; diff --git a/GraphBLAS/@GrB/symrcm.m b/GraphBLAS/@GrB/symrcm.m index 04140c662c..76f68623a4 100644 --- a/GraphBLAS/@GrB/symrcm.m +++ b/GraphBLAS/@GrB/symrcm.m @@ -1,11 +1,11 @@ function p = symrcm (G) -%SYMRCM Reverse Cuthill-McKee ordering of a GraphBLAS matrix. +%SYMRCM reverse Cuthill-McKee ordering. % See 'help symrcm' for details. % -% See also symrcm, GrB/amd, GrB/colamd, GrB/symamd. +% See also GrB/amd, GrB/colamd, GrB/symamd. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. p = builtin ('symrcm', logical (G)) ; diff --git a/GraphBLAS/@GrB/tan.m b/GraphBLAS/@GrB/tan.m new file mode 100644 index 0000000000..06c964dbb6 --- /dev/null +++ b/GraphBLAS/@GrB/tan.m @@ -0,0 +1,18 @@ +function C = tan (G) +%TAN tangent. +% C = tan (G) is the tangent of each entry of G. +% +% See also GrB/tanh, GrB/atan, GrB/atanh, GrB/atan2. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +if (~gb_isfloat (gbtype (G))) + op = 'tan.double' ; +else + op = 'tan' ; +end + +C = GrB (gbapply (op, G)) ; + diff --git a/GraphBLAS/@GrB/tanh.m b/GraphBLAS/@GrB/tanh.m new file mode 100644 index 0000000000..99bf1527cf --- /dev/null +++ b/GraphBLAS/@GrB/tanh.m @@ -0,0 +1,18 @@ +function C = tanh (G) +%TANH hyperbolic tangent. +% C = tanh (G) is the hyperbolic tangent of each entry of G. +% +% See also GrB/tan, GrB/atan, GrB/atanh, GrB/atan2. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +G = G.opaque ; +if (~gb_isfloat (gbtype (G))) + op = 'tanh.double' ; +else + op = 'tanh' ; +end + +C = GrB (gbapply (op, G)) ; + diff --git a/GraphBLAS/@GrB/threads.m b/GraphBLAS/@GrB/threads.m index 5769dc1fdd..e577181cb4 100644 --- a/GraphBLAS/@GrB/threads.m +++ b/GraphBLAS/@GrB/threads.m @@ -1,7 +1,6 @@ -function nthreads = threads (varargin) +function nthreads = threads (nthreads) %GRB.THREADS get/set the max number of threads to use in GraphBLAS. % -% Usage: % nthreads = GrB.threads ; % get the current maximum # of threads % GrB.threads (nthreads) ; % set the maximum # of threads % @@ -18,7 +17,7 @@ % setting reverts to the default number of threads. % % MATLAB can detect the number of physical and logical cores via an -% undocumented builtin function: ncores = feature('numcores'), or via +% undocumented built-in function: ncores = feature('numcores'), or via % maxNumCompThreads. % % Example: @@ -26,13 +25,17 @@ % feature ('numcores') ; % print info about cores % ncores = feature ('numcores') ; % get # of logical cores MATLAB uses % ncores = maxNumCompThreads ; % same as feature ('numcores') -% GrB.threads (2*ncores) ; % GraphBLAS will use at most 2*ncores +% GrB.threads (2*ncores) ; % GraphBLAS will use at most 2*ncores % % threads % % See also feature, maxNumCompThreads, GrB.chunk. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -nthreads = gbthreads (varargin {:}) ; +if (nargin == 0) + nthreads = gbthreads ; +else + nthreads = gbthreads (nthreads) ; +end diff --git a/GraphBLAS/@GrB/times.m b/GraphBLAS/@GrB/times.m index c46df016a2..eef7c0f7d4 100644 --- a/GraphBLAS/@GrB/times.m +++ b/GraphBLAS/@GrB/times.m @@ -5,29 +5,18 @@ % If one is a scalar, the pattern of C is the same as the pattern of the % one matrix. % -% The input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. C is returned as a GraphBLAS matrix. -% % See also GrB/mtimes, GrB.emult, GrB.mxm. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (A)) + A = A.opaque ; +end -if (isscalar (A)) - if (isscalar (B)) - % both A and B are scalars - else - % A is a scalar, B is a matrix - A = GrB.expand (A, B) ; - end -else - if (isscalar (B)) - % A is a matrix, B is a scalar - B = GrB.expand (B, A) ; - else - % both A and B are matrices - end +if (isobject (B)) + B = B.opaque ; end -C = GrB.emult (A, '*', B) ; +C = GrB (gb_emult (A, '*', B)) ; diff --git a/GraphBLAS/@GrB/trans.m b/GraphBLAS/@GrB/trans.m index da3df21a50..7e06ccae23 100644 --- a/GraphBLAS/@GrB/trans.m +++ b/GraphBLAS/@GrB/trans.m @@ -1,30 +1,54 @@ -function Cout = trans (varargin) +function C = trans (arg1, arg2, arg3, arg4, arg5) %GRB.TRANS transpose a sparse matrix. % -% Usage: -% -% Cout = GrB.trans (A, desc) -% Cout = GrB.trans (Cin, accum, A, desc) -% Cout = GrB.trans (Cin, M, A, desc) -% Cout = GrB.trans (Cin, M, accum, A, desc) +% C = GrB.trans (A) +% C = GrB.trans (A, desc) +% C = GrB.trans (Cin, accum, A, desc) +% C = GrB.trans (Cin, M, A, desc) +% C = GrB.trans (Cin, M, accum, A, desc) % % The descriptor is optional. If desc.in0 is 'transpose', then C=A or % C=accum(C,A) is computed, since the default behavior is to transpose % the input matrix. % -% All input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. Cout is returned as a GraphBLAS matrix, by default; -% see 'help GrB/descriptorinfo' for more options. +% For complex matrices, GrB.trans computes the array transpose, not the +% matrix (complex conjugate) transpose. % -% See also transpose, ctranspose. +% See also GrB/transpose, GrB/ctranspose, GrB/conj. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (arg1)) + arg1 = arg1.opaque ; +end + +if (nargin > 1 && isobject (arg2)) + arg2 = arg2.opaque ; +end -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +if (nargin > 2 && isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +switch (nargin) + case 1 + [C, k] = gbtrans (arg1) ; + case 2 + [C, k] = gbtrans (arg1, arg2) ; + case 3 + [C, k] = gbtrans (arg1, arg2, arg3) ; + case 4 + [C, k] = gbtrans (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbtrans (arg1, arg2, arg3, arg4, arg5) ; +end -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - Cout = GrB (gbtrans (args {:})) ; -else - Cout = gbtrans (args {:}) ; +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/transpose.m b/GraphBLAS/@GrB/transpose.m index 2e92c855b4..ed148aaaa8 100644 --- a/GraphBLAS/@GrB/transpose.m +++ b/GraphBLAS/@GrB/transpose.m @@ -1,10 +1,12 @@ function C = transpose (G) -%TRANSPOSE C = G.', array transpose of a GraphBLAS matrix. +%TRANSPOSE C = G.', array transpose. +% C = G.' is the array transpose of G. % -% See also GrB.trans, ctranspose. +% See also GrB.trans, GrB/ctranspose. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB.trans (G) ; +G = G.opaque ; +C = GrB (gbtrans (G)) ; diff --git a/GraphBLAS/@GrB/tricount.m b/GraphBLAS/@GrB/tricount.m index fb7e329b76..545cbc3e3d 100644 --- a/GraphBLAS/@GrB/tricount.m +++ b/GraphBLAS/@GrB/tricount.m @@ -1,6 +1,6 @@ function s = tricount (A, arg2, arg3) %GRB.TRICOUNT count triangles in a matrix. -% s = GrB.tricount (A) counts the number of triangles in the matrix A. +% s = GrB.tricount (A) is the number of triangles in the matrix A. % spones (A) must be symmetric; results are undefined if spones (A) is % unsymmetric. Diagonal entries are ignored. % @@ -12,12 +12,15 @@ % the degrees first. % % See also GrB.ktruss, GrB.entries. -% -% ADDED: sort if warranted. See LAGraph_tricount. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +% NOTE: this is a high-level algorithm that uses GrB objects. [m, n] = size (A) ; if (m ~= n) - gb_error ('A must be square') ; + error ('A must be square') ; end d = [ ] ; @@ -44,7 +47,7 @@ end if (check && ~issymmetric (spones (A))) - gb_error ('pattern of A must be symmetric') ; + error ('pattern of A must be symmetric') ; end if (isequal (class (d), 'GrB')) @@ -62,16 +65,14 @@ end end % sample the degree - p = randperm (n, 1000) ; sample = d (randperm (n, 1000)) ; dmean = full (mean (sample)) ; dmed = full (median (sample)) ; - % fprintf ('mean degree: %g median: %g\n', dmean, dmed) ; if (dmean > 4 * dmed) % sort if the average degree is very high compared to the median - % fprintf ('sorting A first\n') ; [~, p] = sort (d, 'descend') ; - A = A (p,p) ; + % A = A (p,p) ; + A = GrB.extract (A, { p }, { p }) ; clear p end end diff --git a/GraphBLAS/@GrB/tril.m b/GraphBLAS/@GrB/tril.m index 94ab552239..281e6e600e 100644 --- a/GraphBLAS/@GrB/tril.m +++ b/GraphBLAS/@GrB/tril.m @@ -1,5 +1,5 @@ function L = tril (G, k) -%TRIL lower triangular part of a GraphBLAS matrix. +%TRIL lower triangular part of a matrix. % L = tril (G) returns the lower triangular part of G. % % L = tril (G,k) returns the entries on and below the kth diagonal of G, @@ -7,11 +7,18 @@ % % See also GrB/triu. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (G)) + G = G.opaque ; +end if (nargin < 2) k = 0 ; +else + k = gb_get_scalar (k) ; end -L = GrB.select ('tril', G, k) ; + +L = GrB (gbselect ('tril', G, k)) ; diff --git a/GraphBLAS/@GrB/triu.m b/GraphBLAS/@GrB/triu.m index ee71989fea..12e3b35aef 100644 --- a/GraphBLAS/@GrB/triu.m +++ b/GraphBLAS/@GrB/triu.m @@ -1,5 +1,5 @@ function U = triu (G, k) -%TRIU upper triangular part of a GraphBLAS matrix. +%TRIU upper triangular part of a matrix. % U = triu (G) returns the upper triangular part of G. % % U = triu (G,k) returns the entries on and above the kth diagonal of X, @@ -7,11 +7,18 @@ % % See also GrB/tril. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + +if (isobject (G)) + G = G.opaque ; +end if (nargin < 2) k = 0 ; +else + k = gb_get_scalar (k) ; end -U = GrB.select ('triu', G, k) ; + +U = GrB (gbselect ('triu', G, k)) ; diff --git a/GraphBLAS/@GrB/true.m b/GraphBLAS/@GrB/true.m index bfd42187ff..8254cd5564 100644 --- a/GraphBLAS/@GrB/true.m +++ b/GraphBLAS/@GrB/true.m @@ -1,12 +1,21 @@ function C = true (varargin) -%TRUE a GraphBLAS logical matrix with all true values. -% C = true (m, n, 'like', G) or C = ones ([m n], 'like', G) constructs an -% m-by-n GraphBLAS logical matrix C with all entries equal to true. +%TRUE a logical matrix with all true values. % -% See also zeros, false, true. +% C = true (n) ; n-by-n GrB logical matrix of all true entries. +% C = true (m,n) ; m-by-n GrB logical matrix of all true entries. +% C = true ([m,n]) ; m-by-n GrB logical matrix of all true entries. +% C = true (..., type) ; matrix of all true entries of given type. +% C = true (..., 'like', G) ; matrix of all true entries, same type as G. +% +% Since function overloads the MATLAB built-in true(...), at least one +% input must be a GraphBLAS matrix to use this version (for example, +% C = true (GrB (n))). +% +% See also GrB/zeros, GrB/ones, GrB/false. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB.subassign (false (varargin {:}), true) ; +[m, n, ~] = gb_parse_args ('true', varargin {:}) ; +C = GrB (gb_scalar_to_full (m, n, 'logical', true)) ; diff --git a/GraphBLAS/@GrB/type.m b/GraphBLAS/@GrB/type.m index 0a3a54972d..845fe87449 100644 --- a/GraphBLAS/@GrB/type.m +++ b/GraphBLAS/@GrB/type.m @@ -1,29 +1,50 @@ function s = type (X) %GRB.TYPE get the type of a MATLAB or GraphBLAS matrix. % s = GrB.type (X) returns the type of a GraphBLAS matrix X as a string: -% 'double', 'single', 'int8', 'int16', 'int32', 'int64', 'uint8', -% 'uint16', 'uint32', 'uint64', 'logical', or (in the future) 'complex'. -% Note that 'complex' is treated as a type, not an attribute, which -% differs from the MATLAB convention. Complex matrices are not yet -% supported. +% 'logical', 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', +% 'uint32', 'uint64', 'single', 'double', 'single complex', and 'double +% complex'. Note that for GraphBLAS matrices, 'complex' is treated as a +% type, not an attribute, which differs from the MATLAB convention. +% +% For a GraphBLAS matrix X of any type, class (X) returns 'GrB'. +% GraphBLAS does not overload the MATLAB 'class' or 'isobject' functions, +% but it does overload the 'isa' function, which queries the type of a +% GraphBLAS matrix. % % If X is not a GraphBLAS matrix, GrB.type (X) is the same as class (X), -% except when X is a MATLAB double complex matrix, which case GrB.type (X) -% will be 'complex' (in the future). +% except when X is a MATLAB single complex or double complex matrix, in +% which case GrB.type (X) is 'single complex' or 'double complex', +% respectively. The MATLAB class (X) is 'single' if X is single complex +% and 'double' if X is double complex. +% +% Examples: +% +% A = int8 (magic (4)) +% G = GrB (A) +% class (A) +% GrB.type (A) +% class (G) +% GrB.type (G) +% isa (G, 'int8') +% isa (A, 'int8') % -% See also class, GrB. +% A = single (pi + 1i) +% G = GrB (A) +% class (A) +% GrB.type (A) +% class (G) +% GrB.type (G) +% isa (G, 'single complex') +% isa (A, 'single complex') +% +% See also class, isa, GrB/isa, GrB. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -if (isa (X, 'GrB')) - % extract the GraphBLAS opaque matrix struct and then get its type - s = gbtype (X.opaque) ; -elseif (isobject (X)) - % the gbtype mexFunction cannot handle object inputs, so use class (X) - s = class (X) ; -else - % get the type of a MATLAB matrix, cell, char, function_handle, ... - s = gbtype (X) ; +if (isobject (X)) + X = X.opaque ; end +s = gbtype (X) ; + diff --git a/GraphBLAS/@GrB/uint16.m b/GraphBLAS/@GrB/uint16.m index 0808b0768a..db33615f6d 100644 --- a/GraphBLAS/@GrB/uint16.m +++ b/GraphBLAS/@GrB/uint16.m @@ -7,11 +7,13 @@ % To typecast the matrix G to a GraphBLAS sparse uint16 matrix instead, % use C = GrB (G, 'uint16'). % -% See also GrB, double, complex, single, logical, int8, int16, int32, -% int64, uint8, uint32, and uint64. +% See also GrB, GrB/double, GrB/complex, GrB/single, GrB/logical, GrB/int8, +% GrB/int16, GrB/int32, GrB/int64, GrB/uint8, GrB/uint32, GrB/uint64. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = gbfull (G.opaque, 'uint16') ; +G = G.opaque ; +desc.kind = 'full' ; +C = gbfull (G, 'uint16', uint16 (0), desc) ; diff --git a/GraphBLAS/@GrB/uint32.m b/GraphBLAS/@GrB/uint32.m index ce91d05ebd..95874288dd 100644 --- a/GraphBLAS/@GrB/uint32.m +++ b/GraphBLAS/@GrB/uint32.m @@ -7,11 +7,13 @@ % To typecast the matrix G to a GraphBLAS sparse uint32 matrix instead, % use C = GrB (G, 'uint32'). % -% See also GrB, double, complex, single, logical, int8, int16, int32, -% int64, uint8, uint16, and uint64. +% See also GrB, GrB/double, GrB/complex, GrB/single, GrB/logical, GrB/int8, +% GrB/int16, GrB/int32, GrB/int64, GrB/uint8, GrB/uint16, GrB/uint64. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = gbfull (G.opaque, 'uint32') ; +G = G.opaque ; +desc.kind = 'full' ; +C = gbfull (G, 'uint32', uint32 (0), desc) ; diff --git a/GraphBLAS/@GrB/uint64.m b/GraphBLAS/@GrB/uint64.m index ced49a8e95..aea6488e24 100644 --- a/GraphBLAS/@GrB/uint64.m +++ b/GraphBLAS/@GrB/uint64.m @@ -7,11 +7,13 @@ % To typecast the matrix G to a GraphBLAS sparse uint64 matrix instead, % use C = GrB (G, 'uint64'). % -% See also GrB, double, complex, single, logical, int8, int16, int32, -% int64, uint8, uint16, and uint32. +% See also GrB, GrB/double, GrB/complex, GrB/single, GrB/logical, GrB/int8, +% GrB/int16, GrB/int32, GrB/int64, GrB/uint8, GrB/uint16, GrB/uint32. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = gbfull (G.opaque, 'uint64') ; +G = G.opaque ; +desc.kind = 'full' ; +C = gbfull (G, 'uint64', uint64 (0), desc) ; diff --git a/GraphBLAS/@GrB/uint8.m b/GraphBLAS/@GrB/uint8.m index 2a1a8ee31d..d428fbdf06 100644 --- a/GraphBLAS/@GrB/uint8.m +++ b/GraphBLAS/@GrB/uint8.m @@ -7,11 +7,13 @@ % To typecast the matrix G to a GraphBLAS sparse uint8 matrix instead, % use C = GrB (G, 'uint8'). % -% See also GrB, double, complex, single, logical, int8, int16, int32, -% int64, uint16, uint32, and uint64. +% See also GrB, GrB/double, GrB/complex, GrB/single, GrB/logical, GrB/int8, +% GrB/int16, GrB/int32, GrB/int64, GrB/uint16, GrB/uint32, GrB/uint64. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = gbfull (G.opaque, 'uint8') ; +G = G.opaque ; +desc.kind = 'full' ; +C = gbfull (G, 'uint8', uint8 (0), desc) ; diff --git a/GraphBLAS/@GrB/uminus.m b/GraphBLAS/@GrB/uminus.m index 5ee2bd7791..45f90b3c2f 100644 --- a/GraphBLAS/@GrB/uminus.m +++ b/GraphBLAS/@GrB/uminus.m @@ -1,11 +1,12 @@ function C = uminus (G) -%UMINUS negate a GraphBLAS sparse matrix. -% C = -G negates the entries of a GraphBLAS matrix. +%UMINUS negate a matrix. +% C = -G negates the entries of the matrix G. % % See also GrB.apply, GrB/minus, GrB/uplus. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB.apply ('-', G) ; +G = G.opaque ; +C = GrB (gbapply ('-', G)) ; diff --git a/GraphBLAS/@GrB/unopinfo.m b/GraphBLAS/@GrB/unopinfo.m index acd4b2a3b3..35696ad434 100644 --- a/GraphBLAS/@GrB/unopinfo.m +++ b/GraphBLAS/@GrB/unopinfo.m @@ -1,8 +1,6 @@ function unopinfo (op, type) %GRB.UNOPINFO list the details of a GraphBLAS unary operator. % -% Usage -% % GrB.unopinfo % GrB.unopinfo (op) % GrB.unopinfo (op, type) @@ -15,41 +13,88 @@ function unopinfo (op, type) % must be provided, either in the op as GrB.unopinfo ('abs.double'), or in % the second argument, GrB.unopinfo ('abs', 'double'). % -% The MATLAB interface to GraphBLAS provides for 6 different unary -% operators, each of which may be used with any of the 11 types, for a -% total of 6*11 = 66 valid unary operators. Unary operators are defined -% by a string of the form 'op.type', or just 'op'. In the latter case, -% the type defaults to the type of the matrix inputs to the GraphBLAS -% operation. +% The functions z=f(x) are listed below. Unless otherwise specified, +% z and x have the same type. Some functions have synonyms, as listed. +% +% For all 13 types: +% identity z = x also '+', 'uplus' +% ainv z = -x additive inverse, also '-', 'negate', 'uminus' +% minv z = 1/x multiplicative inverse +% one z = 1 does not depend on x, also '1' +% abs z = |x| 'abs.complex' returns a real result +% +% For all 11 real types: +% lnot z = ~(x ~= 0) logical negation (z is 1 or 0, with the +% same type as x), also '~', 'not'. % -% The following unary operators are available. +% For 4 floating-point types (real & complex)x(single & double): +% sqrt z = sqrt (x) square root +% log z = log (x) base-e logarithm +% log2 z = log2 (x) base-2 logarithm +% log10 z = log10 (x) base-10 logarithm +% log1p z = log1p (x) log (x-1), base-e +% exp z = exp (x) base-e exponential, e^x +% pow2 z = pow2 (x) base-2 exponential, 2^x +% expm1 z = exp1m (x) e^x-1 +% sin z = sin (x) sine +% cos z = cos (x) cosine +% tan z = tan (x) tangent +% acos z = acos (x) arc cosine +% asin z = asin (x) arc sine +% atan z = atan (x) arc tangent +% sinh z = sinh (x) hyperbolic sine +% cosh z = cosh (x) hyperbolic cosine +% tanh z = tanh (x) hyperbolic tangent +% asinh z = asinh (x) inverse hyperbolic sine +% acosh z = acosh (x) inverse hyperbolic cosine +% atanh z = atanh (x) inverse hyperbolic tangent +% signum z = signum (x) signum function, also 'sign' +% ceil z = ceil (x) ceiling +% floor z = floor (x) floor +% round z = round (x) round to nearest +% trunc z = trunc (x) truncate, also 'fix' % -% operator name(s) f(x,y) | operator names(s) f(x,y) -% ---------------- ------ | ----------------- ------ -% identity x | lnot not ~ ~x -% ainv - negate -x | one 1 1 -% minv 1/x | abs abs(x) +% For 'single complex' and 'double complex' only: +% creal z = real (x) real part of x (z is real), also 'real' +% cimag z = imag (x) imag. part of x (z is real), also 'imag' +% carg z = carg (x) phase angle (z is real), also 'angle' +% conj z = conj (x) complex conjugate (z is complex) % -% The logical operator, lnot, also comes in 11 types. z = lnot.double (x) -% tests the condition (x ~= 0), and returns the double value 1.0 if true, -% or 0.0 if false. +% For all 4 floating-point types (result is logical): +% isinf z = isinf (x) true if x is +Inf or -Inf +% isnan z = isnan (x) true if x is NaN +% isfinite z = isfinite (x) true if x is finite +% +% For single and double (result same type as input): +% lgamma z = lgamma (x) log of gamma function, also 'gammaln' +% tgamma z = tgamma (x) gamma function, also 'gamma' +% erf z = erf (x) error function +% erfc z = erfc (x) complementary error function +% frexpx z = frexpx (x) mantissa from ANSI C11 frexp function +% frexpe z = frexpe (x) exponent from ANSI C11 frexp function +% The MATLAB [f,e]=log2(x) returns +% f = frexpx (x) and e = frexpe (x). +% +% For integer types only (result is same type as input): +% bitcmp z = ~(x) bitwise complement, also 'bitnot' % % Example: % % % valid unary operators +% GrB.unopinfo ('+.double') ; % also a valid binary operator % GrB.unopinfo ('abs.double') ; % GrB.unopinfo ('not.int32') ; +% GrB.unopinfo ('pow2.double') ; % also a valid binary operator +% GrB.binopinfo ('pow2.double') ; % % % invalid unary operator (generates an error; this is a binary op): -% GrB.unopinfo ('+.double') ; +% GrB.unopinfo ('*.double') ; % % See also GrB.binopinfo, GrB.descriptorinfo, GrB.monoidinfo, % GrB.selectopinfo, GrB.semiringinfo. -% FUTURE: add complex unary operators - -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. if (nargin == 0) help GrB.unopinfo diff --git a/GraphBLAS/@GrB/uplus.m b/GraphBLAS/@GrB/uplus.m index b9cedbc971..2ab54d0af4 100644 --- a/GraphBLAS/@GrB/uplus.m +++ b/GraphBLAS/@GrB/uplus.m @@ -5,8 +5,8 @@ % % See also GrB/uminus. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. C = G ; diff --git a/GraphBLAS/@GrB/vertcat.m b/GraphBLAS/@GrB/vertcat.m index 3ca622788f..ca20961fa4 100644 --- a/GraphBLAS/@GrB/vertcat.m +++ b/GraphBLAS/@GrB/vertcat.m @@ -1,36 +1,43 @@ function C = vertcat (varargin) -%VERTCAT Vertical concatenation. +%VERTCAT vertical concatenation. % [A ; B] is the vertical concatenation of A and B. -% A and B may be GraphBLAS or MATLAB matrices, in any combination. % Multiple matrices may be concatenated, as [A ; B ; C ; ...]. +% If the matrices have different types, the type is determined +% according to the rules in GrB.optype. % -% See also horzcat, GrB/horzcat. +% See also GrB/horzcat, GrB.optype. % FUTURE: this will be much faster when it is a mexFunction. % The version below requires a sort in GrB.build. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. % determine the size of each matrix and the size of the result nmatrices = length (varargin) ; nvals = zeros (1, nmatrices) ; nrows = zeros (1, nmatrices) ; A = varargin {1} ; -[m, n] = size (A) ; -nvals (1) = GrB.entries (A) ; +if (isobject (A)) + A = A.opaque ; +end +[m, n, type] = gbsize (A) ; +nvals (1) = gbnvals (A) ; nrows (1) = m ; -type = GrB.type (A) ; clear A for k = 2:nmatrices - B = varargin {k} ; - [m, n2] = size (B) ; + A = varargin {k} ; + if (isobject (A)) + A = A.opaque ; + end + [m2, n2, type2] = gbsize (A) ; if (n ~= n2) - gb_error ('Dimensions of arrays being concatenated are not consistent'); + error ('Dimensions of arrays not consistent') ; end - nvals (k) = GrB.entries (B) ; - nrows (k) = m ; - clear B ; + nvals (k) = gbnvals (A) ; + nrows (k) = m2 ; + type = gboptype (type, type2) ; + clear A ; end nrows = [0 cumsum(nrows)] ; nvals = [0 cumsum(nvals)] ; @@ -45,15 +52,19 @@ % fill the I,J,X arrays desc.base = 'zero-based' ; for k = 1:nmatrices - [i, j, x] = GrB.extracttuples (varargin {k}, desc) ; + A = varargin {k} ; + if (isobject (A)) + A = A.opaque ; + end + [i, j, x] = gbextracttuples (A, desc) ; moffset = int64 (nrows (k)) ; - koffset = nvals (k) ; - kvals = GrB.entries (varargin {k}) ; - I ((koffset+1):(koffset+kvals)) = i + moffset ; - J ((koffset+1):(koffset+kvals)) = j ; - X ((koffset+1):(koffset+kvals)) = x ; + k1 = nvals (k) + 1 ; + k2 = nvals (k+1) ; + I (k1:k2) = i + moffset ; + J (k1:k2) = j ; + X (k1:k2) = x ; end % build the output matrix -C = GrB.build (I, J, X, m, n, desc) ; +C = GrB (gbbuild (I, J, X, m, n, desc)) ; diff --git a/GraphBLAS/@GrB/vreduce.m b/GraphBLAS/@GrB/vreduce.m index 05297f6a2f..f0faaca777 100644 --- a/GraphBLAS/@GrB/vreduce.m +++ b/GraphBLAS/@GrB/vreduce.m @@ -1,42 +1,69 @@ -function Cout = vreduce (varargin) -%GRB.REDUCE reduce a matrix to a vector. +function C = vreduce (arg1, arg2, arg3, arg4, arg5, arg6) +%GRB.VREDUCE reduce a matrix to a vector. % -% Usage: +% C = GrB.vreduce (monoid, A) +% C = GrB.vreduce (monoid, A, desc) +% C = GrB.vreduce (Cin, M, monoid, A) +% C = GrB.vreduce (Cin, M, monoid, A, desc) +% C = GrB.vreduce (Cin, accum, monoid, A) +% C = GrB.vreduce (Cin, accum, monoid, A, desc) +% C = GrB.vreduce (Cin, M, accum, monoid, A) +% C = GrB.vreduce (Cin, M, accum, monoid, A, desc) % -% Cout = GrB.vreduce (monoid, A) -% Cout = GrB.vreduce (monoid, A, desc) -% Cout = GrB.vreduce (Cin, M, monoid, A) -% Cout = GrB.vreduce (Cin, M, monoid, A, desc) -% Cout = GrB.vreduce (Cin, accum, monoid, A) -% Cout = GrB.vreduce (Cin, accum, monoid, A, desc) -% Cout = GrB.vreduce (Cin, M, accum, monoid, A) -% Cout = GrB.vreduce (Cin, M, accum, monoid, A, desc) +% The monoid and A arguments are required. All others are optional. % -% The monoid and A arguments are required. All others are optional. The -% valid monoids are: '+', '*', 'max', and 'min' for all but the 'logical' -% type, and '|', '&', 'xor', and 'ne' for the 'logical' type. See 'help -% GrB.monoidinfo' for more details. +% Monoids for real non-logical types: '+', '*', 'max', 'min', 'any' +% For logical: '|', '&', 'xor', 'eq', 'any' +% For complex types: '+', '*', 'any' +% For integer types: 'bitor', 'bitand', 'bitxor', 'bitxnor' % -% By default, each row of A is reduced to a scalar. If Cin is not -% present, Cout (i) = reduce (A (i,:)). In this case, Cin and Cout are -% column vectors of size m-by-1, where A is m-by-n. If desc.in0 is -% 'transpose', then A.' is reduced to a column vector; Cout (j) = reduce -% (A (:,j)). In this case, Cin and Cout are column vectors of size -% n-by-1, if A is m-by-n. +% See 'help GrB.monoidinfo' for more details on the available monoids. % -% All input matrices may be either GraphBLAS and/or MATLAB matrices, in -% any combination. Cout is returned as a GraphBLAS matrix, by default; -% see 'help GrB/descriptorinfo' for more options. +% By default, each row of A is reduced to a scalar. If Cin is not present, +% C (i) = reduce (A (i,:)). In this case, Cin and C are column vectors of +% size m-by-1, where A is m-by-n. If desc.in0 is 'transpose', then A.' is +% reduced to a column vector; C (j) = reduce (A (:,j)). In this case, Cin +% and C are column vectors of size n-by-1, if A is m-by-n. % -% See also GrB.reduce, sum, prod, max, min. +% See also GrB.reduce, GrB/sum, GrB/prod, GrB/max, GrB/min. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -[args, is_gb] = gb_get_args (varargin {:}) ; -if (is_gb) - Cout = GrB (gbvreduce (args {:})) ; -else - Cout = gbvreduce (args {:}) ; +if (isobject (arg1)) + arg1 = arg1.opaque ; +end + +if (isobject (arg2)) + arg2 = arg2.opaque ; +end + +if (nargin > 2 && isobject (arg3)) + arg3 = arg3.opaque ; +end + +if (nargin > 3 && isobject (arg4)) + arg4 = arg4.opaque ; +end + +if (nargin > 4 && isobject (arg5)) + arg5 = arg5.opaque ; +end + +switch (nargin) + case 2 + [C, k] = gbvreduce (arg1, arg2) ; + case 3 + [C, k] = gbvreduce (arg1, arg2, arg3) ; + case 4 + [C, k] = gbvreduce (arg1, arg2, arg3, arg4) ; + case 5 + [C, k] = gbvreduce (arg1, arg2, arg3, arg4, arg5) ; + case 6 + [C, k] = gbvreduce (arg1, arg2, arg3, arg4, arg5, arg6) ; +end + +if (k == 0) + C = GrB (C) ; end diff --git a/GraphBLAS/@GrB/xor.m b/GraphBLAS/@GrB/xor.m index 28a1153456..685245d6de 100644 --- a/GraphBLAS/@GrB/xor.m +++ b/GraphBLAS/@GrB/xor.m @@ -2,40 +2,47 @@ %XOR logical exclusive OR. % C = xor (A,B) is the element-by-element logical OR of A and B. One or % both may be scalars. Otherwise, A and B must have the same size. -% GraphBLAS and MATLAB matrices may be combined. % -% See also GrB/and, GrB/or. +% See also GrB/and, GrB/or, GrB/not. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -if (isscalar (A)) - if (isscalar (B)) +if (isobject (A)) + A = A.opaque ; +end + +if (isobject (B)) + B = B.opaque ; +end + +if (gb_isscalar (A)) + if (gb_isscalar (B)) % A and B are scalars - C = GrB.emult (A, 'xor.logical', B) ; + C = GrB (gbemult (A, 'xor.logical', B)) ; else % A is a scalar, B is a matrix - if (gb_get_scalar (A) == 0) + if (gb_scalar (A) == 0) % A is false, so C is B typecasted to logical - C = GrB (B, 'logical') ; + C = GrB (gbnew (B, 'logical')) ; else % A is true, so C is a full matrix the same size as B - C = not (B) ; + C = GrB (gbapply ('~', gbfull (B, 'logical'))) ; end end else - if (isscalar (B)) + if (gb_isscalar (B)) % A is a matrix, B is a scalar - if (gb_get_scalar (B) == 0) + if (gb_scalar (B) == 0) % B is false, so C is A typecasted to logical - C = GrB (A, 'logical') ; + C = GrB (gbnew (A, 'logical')) ; else % B is true, so C is a full matrix the same size as A - C = not (A) ; + C = GrB (gbapply ('~', gbfull (A, 'logical'))) ; end else % both A and B are matrices. C is the set union of A and B - C = GrB.eadd (A, 'xor.logical', B) ; + C = GrB (gbeadd (A, 'xor.logical', B)) ; end end diff --git a/GraphBLAS/@GrB/zeros.m b/GraphBLAS/@GrB/zeros.m index 32fdf1ff75..43402124dd 100644 --- a/GraphBLAS/@GrB/zeros.m +++ b/GraphBLAS/@GrB/zeros.m @@ -1,30 +1,21 @@ function C = zeros (varargin) -%ZEROS an all-zero matrix, the same type as G. -% C = zeros (m, n, 'like', G) or C = zeros ([m n], 'like', G) returns -% an m-by-n matrix with no entries, of the same type as G. +%ZEROS a matrix with no entries. +% +% C = zeros (n) ; n-by-n GrB double matrix with no entries. +% C = zeros (m,n) ; m-by-n GrB double matrix with no entries. +% C = zeros ([m,n]) ; m-by-n GrB double matrix with no entries. +% C = zeros (..., type) ; empty matrix of given type. +% C = zeros (..., 'like', G) ; empty matrix, same type as G. +% +% Since function overloads the MATLAB built-in zeros(...), at least one +% input must be a GraphBLAS matrix to use this version (for example, +% C = zeros (GrB (n))). Alternatively, C = GrB (n,n) can be used. % % See also GrB/ones, GrB/false, GrB/true. -% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. -% http://suitesparse.com See GraphBLAS/Doc/License.txt for license. - -G = varargin {end} ; -if (nargin == 4) - if (~isequal (varargin {3}, 'like')) - gb_error ('usage: zeros (m, n, ''like'', G)') ; - end - m = varargin {1} ; - n = varargin {2} ; -elseif (nargin == 3) - if (~isequal (varargin {2}, 'like')) - gb_error ('usage: zeros ([m n], ''like'', G)') ; - end - mn = varargin {1} ; - m = mn (1) ; - n = mn (2) ; -else - gb_error ('usage: zeros (m, n, ''like'', G)') ; -end +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. -C = GrB (m, n, GrB.type (G)) ; +[m, n, type] = gb_parse_args ('zeros', varargin {:}) ; +C = GrB (gbnew (m, n, type)) ; diff --git a/GraphBLAS/Contents.m b/GraphBLAS/Contents.m index 337bd3a690..9f1353dd25 100644 --- a/GraphBLAS/Contents.m +++ b/GraphBLAS/Contents.m @@ -15,65 +15,12 @@ % C = GrB (..., format) ; create in a specified format % % The type can be 'double', 'single', 'logical', 'int8', 'int16', 'int32', -% 'int64', 'uint8', 'uint16', 'uint32', or 'uint64'. The format is 'by row' or -% 'by col'. +% 'int64', 'uint8', 'uint16', 'uint32', 'uint64', 'double complex' or 'single +% complex'. The format is 'by row' or 'by col'. % -% Methods that overload the MATLAB function of the same name; at least -% one of the inputs must be a GraphBLAS matrix: -% -% fix isreal single -% abs flip isscalar size -% all floor issparse sparse -% amd fprintf issymmetric spfun -% and full istril spones -% any graph istriu sprand -% assert int16 isvector sprandn -% bandwidth int32 kron sprandsym -% ceil int64 length sprintf -% colamd int8 logical sqrt -% complex isa max sum -% conj isbanded min symamd -% diag isdiag nnz symrcm -% digraph isempty nonzeros tril -% disp isequal norm triu -% display isfinite numel true -% dmperm isfloat nzmax uint16 -% double ishermitian ones uint32 -% eig isinf prod uint64 -% end isinteger real uint8 -% eps islogical repmat xor -% etree ismatrix reshape zeros -% false isnan round -% find isnumeric sign -% -% Operator overloading (A and/or B a GraphBLAS matrix, C a GraphBLAS matrix): -% -% A+B A-B A*B A.*B A./B A.\B A.^b A/b C=A(I,J) -% -A +A ~A A' A.' A&B A|B b\A C(I,J)=A -% A~=B A>B A==B A<=B A>=B A 0. The method is based on LAGraph_sssp12. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + %------------------------------------------------------------------------------- % check inputs %------------------------------------------------------------------------------- diff --git a/GraphBLAS/GAP/gap_sssp12c.m b/GraphBLAS/GAP/gap_sssp12c.m index 6b43864ff2..ca0ec9f772 100644 --- a/GraphBLAS/GAP/gap_sssp12c.m +++ b/GraphBLAS/GAP/gap_sssp12c.m @@ -5,6 +5,9 @@ % only positive entries. The method is based on LAGraph_sssp12c. This is % slower than gap_sssp12. +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. + %------------------------------------------------------------------------------- % check inputs %------------------------------------------------------------------------------- diff --git a/GraphBLAS/GAP/tricount.m b/GraphBLAS/GAP/tricount.m index 4135b4e5b6..af5dc2df58 100644 --- a/GraphBLAS/GAP/tricount.m +++ b/GraphBLAS/GAP/tricount.m @@ -12,8 +12,9 @@ % the degrees first. % % See also GrB.ktruss, GrB.entries. -% -% ADDED: sort if warranted. See LAGraph_tricount. + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights +% Reserved. http://suitesparse.com. See GraphBLAS/Doc/License.txt. [m, n] = size (A) ; if (m ~= n) diff --git a/GraphBLAS/GAP/typescript_Mar9b_final.txt b/GraphBLAS/GAP/typescript_Mar9b_final.txt index 68f50d010a..a5c636be8a 100644 --- a/GraphBLAS/GAP/typescript_Mar9b_final.txt +++ b/GraphBLAS/GAP/typescript_Mar9b_final.txt @@ -41,442 +41,6 @@ me = GraphBLAS not initialized >> cd ../# @Gr   @GrB/pri   private/ >> gbmake -[?1h=[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_assign.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_binop_to_monoid.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_by_col.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_default_format.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_export.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_export_to_mxfull.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_export_to_mxsparse.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_export_to_mxstruct.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_find_dot.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_first_binop.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_get_deep.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_get_format.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_get_mxargs.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_get_shallow.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_is_all.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_is_equal.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_is_shallow.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_is_vector.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_matrix_assign_scalar.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxarray_is_empty.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxarray_is_scalar.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxarray_to_descriptor.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxarray_to_list.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxarray_type.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxcell_to_index.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxfree.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxstring_to_binop.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxstring_to_format.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxstring_to_monoid.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxstring_to_selectop.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxstring_to_semiring.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxstring_to_string.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxstring_to_type.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_mxstring_to_unop.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_norm.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_norm_kind.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_semiring.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_string_and_type_to_binop.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_string_and_type_to_unop.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_string_to_binop.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_string_to_monoid.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_string_to_selectop.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_string_to_semiring.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_string_to_type.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_string_to_unop.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_type_to_mxstring.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_typecast.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/util/gb_usage.c -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 125)] -[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbapply.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbassign.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbbinopinfo.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbbuild.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbburble.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbchunk.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbdegree.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbdescriptorinfo.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbdisp.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbeadd.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbemult.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbextract.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbextracttuples.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbextractvalues.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbformat.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbfull.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbisequal.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbkronecker.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gblogassign.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gblogextract.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbmonoidinfo.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbmxm.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbnew.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbnorm.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbnormdiff.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbnvals.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbreduce.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbselect.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbselectopinfo.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbsemiringinfo.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbsetup.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbsize.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbsparse.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbsubassign.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbthreads.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbtrans.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbtype.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbunopinfo.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=mex -L'/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/../../../build' -silent -O -R2018a CFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" CXXFLAGS="$CXXFLAGS -fopenmp -fPIC -Wno-pragmas" LDFLAGS="$LDFLAGS -fopenmp -fPIC" -Iutil -I../../../Include -I../../../Source -I../../../Source/Template '/home/faculty/davis/sparse/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbvreduce.c' gb_assign.o gb_binop_to_monoid.o gb_by_col.o gb_default_format.o gb_export.o gb_export_to_mxfull.o gb_export_to_mxsparse.o gb_export_to_mxstruct.o gb_find_dot.o gb_first_binop.o gb_get_deep.o gb_get_format.o gb_get_mxargs.o gb_get_shallow.o gb_is_all.o gb_is_equal.o gb_is_shallow.o gb_is_vector.o gb_matrix_assign_scalar.o gb_mxarray_is_empty.o gb_mxarray_is_scalar.o gb_mxarray_to_descriptor.o gb_mxarray_to_list.o gb_mxarray_type.o gb_mxcell_to_index.o gb_mxfree.o gb_mxstring_to_binop.o gb_mxstring_to_format.o gb_mxstring_to_monoid.o gb_mxstring_to_selectop.o gb_mxstring_to_semiring.o gb_mxstring_to_string.o gb_mxstring_to_type.o gb_mxstring_to_unop.o gb_norm.o gb_norm_kind.o gb_semiring.o gb_string_and_type_to_binop.o gb_string_and_type_to_unop.o gb_string_to_binop.o gb_string_to_monoid.o gb_string_to_selectop.o gb_string_to_semiring.o gb_string_to_type.o gb_string_to_unop.o gb_type_to_mxstring.o gb_typecast.o gb_usage.o -lgraphblas -[?1h=[?1h=[?1h=[Warning: You are using gcc version '5.4.0'. The version of gcc is not supported. The version currently -supported with MEX is '6.3.x'. For a list of currently supported compilers see: -https://www.mathworks.com/support/compilers/current_release.] -[> In gbmake (line 156)] -[?1h=[?1h=[?1h=>> pwd ans = diff --git a/GraphBLAS/README.md b/GraphBLAS/README.md index 5f608ef3d1..7f361b655c 100644 --- a/GraphBLAS/README.md +++ b/GraphBLAS/README.md @@ -97,18 +97,25 @@ error messages during the test. This is expected. # FUTURE: Not yet supported for GrB matrices in MATLAB: linear indexing - complex matrices 2nd output for [x,i] = max (...) and [x,i] = min (...); needs modified reduction methods inside GraphBLAS 'includenan' for min and max + min and max for complex matrices singleton expansion 3D and higher dimensional matrices: this might be done by converting the higher dimensioal - indices down to a large 2D space, ad relying on hypersparsity. - saturating element-wise binary and unary operators for integers + indices down to a large 2D space, and relying on hypersparsity. + saturating element-wise binary and unary operators for integers. + See also the discussion in the User Guide, and the details + in MATLAB_vs_GraphBLAS.txt in this folder. The last two features don't exist for MATLAB sparse matrices. +These features are supported, but are not as fast as they could be: + + concatenation: [A B], [A;B], and the built-in functions: bandwidth, eps, + isbanded, isdiag, ishermitian, issymmetric, istril, istriu, spfun. + For Windows: Microsoft Visual Studio does not support OpenMP tasking, which means that the internal sort is not parallel, but sequential. This affects the performance of GrB.build, and some uses of matrix diff --git a/GraphBLAS/demo/Contents.m b/GraphBLAS/demo/Contents.m index 80eb1166d1..34bae91037 100644 --- a/GraphBLAS/demo/Contents.m +++ b/GraphBLAS/demo/Contents.m @@ -7,10 +7,16 @@ % graphblas_demo - GraphBLAS demo, for publish command % graphblas_demo2 - GraphBLAS demo2, for publish command % -% To run all the demos, use these two commands: +% dnn_mat2gb - convert MATLAB dnn problem to GrB +% dnn_run - run the DNN for the MIT Challenge +% mxm_demo - performance test of real and complex A*B % -% gbdemo -% gbdemo2 +% Folders and other files: +% +% dnn_results - DNN performance results +% html - output of graphblas_demo +% mxm_demo_DellXPS13.txt - mxm_demo results on Intel Core i7-8565U (4 core) +% mxm_demo_DGX_Station.txt - mxm_demo results on Intel Xeon E5-2689 (20 core) % SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved. % http://suitesparse.com See GraphBLAS/Doc/License.txt for license. diff --git a/GraphBLAS/demo/dnn_results/dnn_summary.tex b/GraphBLAS/demo/dnn_results/dnn_summary.tex index 7b51b147db..b6cce83049 100644 --- a/GraphBLAS/demo/dnn_results/dnn_summary.tex +++ b/GraphBLAS/demo/dnn_results/dnn_summary.tex @@ -110,10 +110,10 @@ \section{The C code} for (int layer = 0 ; layer < nlayers ; layer++) { // Y = Y * W [layer], using the conventional PLUS_TIMES semiring - GrB_mxm (Y, NULL, NULL, GxB__PLUS_TIMES_FP32, + GrB_mxm (Y, NULL, NULL, GxB_PLUS_TIMES_FP32, ((layer == 0) ? Y0 : Y), W [layer], NULL) ; // Y = Y * Bias [layer], using the PLUS_PLUS semiring. - GrB_mxm (Y, NULL, NULL, GxB__PLUS_PLUS_FP32, Y, Bias [layer], NULL) ; + GrB_mxm (Y, NULL, NULL, GxB_PLUS_PLUS_FP32, Y, Bias [layer], NULL) ; // delete entries from Y: keep only those entries greater than zero GxB_select (Y, NULL, NULL, GxB_GT_ZERO, Y, NULL, NULL) ; // threshold maximum values: Y (Y > 32) = 32 diff --git a/GraphBLAS/demo/graphblas_demo.m b/GraphBLAS/demo/graphblas_demo.m index 46a6b523fa..b8f3f44c84 100644 --- a/GraphBLAS/demo/graphblas_demo.m +++ b/GraphBLAS/demo/graphblas_demo.m @@ -11,16 +11,17 @@ % GraphBLAS is not only useful for creating graph algorithms; it also % supports a wide range of sparse matrix data types and operations. % MATLAB can compute C=A*B with just two semirings: 'plus.times.double' -% and 'plus.times.complex' for complex matrices. GraphBLAS has 1,040 +% and 'plus.times.complex' for complex matrices. GraphBLAS has 1,473 % unique built-in semirings, such as 'max.plus' % (https://en.wikipedia.org/wiki/Tropical_semiring). These semirings can % be used to construct a wide variety of graph algorithms, based on % operations on sparse adjacency matrices. % -% GraphBLAS supports sparse double and single precision matrices, -% logical, and sparse integer matrices: int8, int16, int32, int64, uint8, -% uint16, uint32, and uint64. Complex matrices will be added in the -% future. +% MATLAB and GraphBLAS both provide sparse matrices of type double, +% logical, and double complex. GraphBLAS adds sparse matrices of type: +% single, int8, int16, int32, int64, uint8, uint16, uint32, uint64, and +% single complex (with MATLAB matrices, these types can only be held in +% full matrices). clear GrB.clear @@ -88,8 +89,7 @@ % '+.*.complex' semirings. A semiring is defined in terms of a string, % 'add.mult.type', where 'add' is a monoid that takes the place of the % additive operator, 'mult' is the multiplicative operator, and 'type' is -% the data type for the two inputs to the mult operator (the type -% defaults to the type of A for C=A*B). +% the data type for the two inputs to the mult operator. % % In the standard semiring, C=A*B is defined as: % @@ -122,7 +122,9 @@ %% The max.plus tropical semiring % Here are details of the "max.plus" tropical semiring. The identity -% value is -inf since max(x,-inf) = max (-inf,x) = -inf for any x. +% value is -inf since max(x,-inf) = max (-inf,x) = x for any x. +% The identity for the conventional "plus.times" semiring is zero, +% since x+0 = 0+x = x for any x. GrB.semiringinfo ('max.+.double') ; @@ -161,12 +163,10 @@ % The C interface for SuiteSparse:GraphBLAS allows for arbitrary types % and operators to be constructed. However, the MATLAB interface to % SuiteSparse:GraphBLAS is restricted to pre-defined types and operators: -% a mere 11 types, 66 unary operators, 275 binary operators, 44 monoids, -% 16 select operators, and 1,865 semirings (1,040 of which are unique, +% a mere 13 types, 204 unary operators, 385 binary operators, 77 monoids, +% 16 select operators, and 2,438 semirings (1,473 of which are unique, % since some binary operators are equivalent: 'min.logical' and -% '&.logical' are the same thing, for example). The complex type and -% its binary operators, monoids, and semirings will be added in the -% near future. +% '&.logical' are the same thing, for example). % % That gives you a lot of tools to create all kinds of interesting % graph algorithms. For example: @@ -177,7 +177,7 @@ % % See 'help GrB.binopinfo' for a list of the binary operators, and % 'help GrB.monoidinfo' for the ones that can be used as the additive -% monoid in a semiring. +% monoid in a semiring. 'help GrB.unopinfo' lists the unary operators. %% help GrB.binopinfo @@ -185,6 +185,9 @@ %% help GrB.monoidinfo +%% +help GrB.unopinfo + %% Element-wise operations % Binary operators can be used in element-wise matrix operations, like % C=A+B and C=A.*B. For the matrix addition C=A+B, the pattern of C is @@ -233,11 +236,12 @@ %% Overloaded operators % The following operators all work as you would expect for any matrix. % The matrices A and B can be GraphBLAS matrices, or MATLAB sparse or -% dense matrices, in any combination, or scalars where appropriate: +% dense matrices, in any combination, or scalars where appropriate, +% The matrix M is logical (MATLAB or GraphBLAS): % -% A+B A-B A*B A.*B A./B A.\B A.^b A/b C=A(I,J) -% -A +A ~A A' A.' A&B A|B b\A C(I,J)=A -% A~=B A>B A==B A<=B A>=B AB A==B A<=B A>=B A 0.5, 3) ; % in GraphBLAS C1 = GrB (A) ; C1 (A > .5) = 3 % also in GraphBLAS -C2 = A ; C2 (A > .5) = 3 % in MATLAB +C2 = A ; C2 (A > .5) = 3 % in MATLAB err = norm (C - C1, 1) err = norm (C - C2, 1) @@ -455,35 +459,23 @@ % Furthermore, C=A*B is not defined for integer types in MATLAB, except % when A and/or B are scalars. % -% GraphBLAS supports all of those types for its sparse matrices (except -% for complex, which will be added in the future). All operations are -% supported, including C=A*B when A or B are any integer type, for all -% 1,865 semirings (1,040 of which are unique). +% GraphBLAS supports all of those types for its sparse matrices. All +% operations are supported, including C=A*B when A or B are any integer +% type, in 1000s of semirings. % % However, integer arithmetic differs in GraphBLAS and MATLAB. In % MATLAB, integer values saturate if they exceed their maximum value. In % GraphBLAS, integer operators act in a modular fashion. The latter is % essential when computing C=A*B over a semiring. A saturating integer % operator cannot be used as a monoid since it is not associative. -% -% The C API for GraphBLAS allows for the creation of arbitrary -% user-defined types, so it would be possible to create different binary -% operators to allow element-wise integer operations to saturate, -% perhaps: -% -% C = GrB.eadd('+saturate',A,B) -% -% This would require an extension to this MATLAB interface. %% C = uint8 (magic (3)) ; G = GrB (C) ; C1 = C * 40 -C2 = G * 40 -C3 = double (G) * 40 ; +C2 = G * uint8 (40) S = double (C1 < 255) ; assert (isequal (double (C1).*S, double (C2).*S)) -assert (isequal (nonzeros (C2), double (mod (nonzeros (C3), 256)))) %% An example graph algorithm: breadth-first search % The breadth-first search of a graph finds all nodes reachable from the @@ -514,12 +506,11 @@ matlab_time / gb_time) ; %% Example graph algorithm: Luby's method in GraphBLAS -% The GrB.mis.m function is variant of Luby's randomized algorithm [Luby +% The GrB.mis function is variant of Luby's randomized algorithm [Luby % 1985]. It is a parallel method for finding an maximal independent set -% of nodes, where no two nodes are adjacent. See the -% GraphBLAS/@GrB/GrB.mis.m function for details. The graph must be -% symmetric with a zero-free diagonal, so A is symmetrized first and any -% diagonal entries are removed. +% of nodes, where no two nodes are adjacent. See the GraphBLAS/@GrB/mis.m +% function for details. The graph must be symmetric with a zero-free +% diagonal, so A is symmetrized first and any diagonal entries are removed. A = GrB (A) ; A = GrB.offdiag (A|A') ; @@ -612,7 +603,9 @@ % Thus, to compute C = A (start:inc:fini) for very huge matrices, % you need to use use a cell array to represent the colon notation, % as { start, inc, fini }, instead of start:inc:fini. See -% 'help GrB.extract' and 'help.gbsubassign' for, for C(I,J)=A. The +% 'help GrB.extract', 'help GrB.assign' for the functional form. +% For the overloaded syntax C(I,J)=A and C=A(I,J), see +% 'help GrB/subsasgn' and 'help GrB/subsfref'. The cell array % syntax isn't conventional, but it is far faster than the MATLAB % colon notation for objects, and takes far less memory when I is huge. @@ -683,9 +676,7 @@ % % gbdemo2 (20000) % -% assuming you have enough memory. The gbdemo2 is not part of this demo -% since it can take a long time; it tries a range of problem sizes, -% and each one takes several minutes in MATLAB. +% assuming you have enough memory. %% Sparse logical indexing is much, much faster in GraphBLAS % The mask in GraphBLAS acts much like logical indexing in MATLAB, but it @@ -704,7 +695,7 @@ % GraphBLAS can also compute C (M) = A (M) using overloaded operators % for subsref and subsasgn, but C = GrB.assign (C, M, A) is a bit faster. % -% First, both methods in GraphBLAS (both are very fast): +% Here are both methods in GraphBLAS (both are very fast). Setting up: clear n = 4000 ; @@ -717,7 +708,8 @@ nnz(C), nnz(M), nnz(A)) ; fprintf ('\nsetup time: %g sec\n', t_setup) ; -% include the time to convert C1 from a GraphBLAS +%% First method in GraphBLAS, with GrB.assign +% Including the time to convert C1 from a GraphBLAS % matrix to a MATLAB sparse matrix: tic C1 = GrB.assign (C, M, A) ; @@ -725,6 +717,7 @@ gb_time = toc ; fprintf ('\nGraphBLAS time: %g sec for GrB.assign\n', gb_time) ; +%% Second method in GraphBLAS, with C(M)=A(M) % now using overloaded operators, also include the time to % convert back to a MATLAB sparse matrix, for good measure: A2 = GrB (A) ; @@ -735,7 +728,7 @@ gb_time2 = toc ; fprintf ('\nGraphBLAS time: %g sec for C(M)=A(M)\n', gb_time2) ; -%% +%% Now with MATLAB matrices, with C(M)=A(M) % Please wait, this will take about 10 minutes or so ... tic @@ -766,26 +759,10 @@ % as C(I,J)=A. However, in its MATLAB interface, this would require a % MATLAB mexFunction to modify its inputs. That breaks the MATLAB API % standard, so it cannot be safely done. As a result, using GraphBLAS -% via its MATLAB interface can be slower than when using its C API. This -% restriction would not be a limitation if GraphBLAS were to be -% incorporated into MATLAB itself, but there is likely no way to do this -% in a mexFunction interface to GraphBLAS. +% via its MATLAB interface can be slower than when using its C API. %% -% (2) Complex matrices: -% -% GraphBLAS can operate on matrices with arbitrary user-defined types and -% operators. The only constraint is that the type be a fixed sized -% typedef that can be copied with the ANSI C memcpy; variable-sized types -% are not yet supported. However, in this MATLAB interface, -% SuiteSparse:GraphBLAS has access to only predefined types, operators, -% and semirings. Complex types and operators will be added to this -% MATLAB interface in the future. They already appear in the C version -% of GraphBLAS, with user-defined operators in -% GraphBLAS/Demo/Source/usercomplex.c. - -%% -% (3) Integer element-wise operations: +% (2) Integer element-wise operations: % % Integer operations in MATLAB saturate, so that uint8(255)+1 is 255. To % allow for integer monoids, GraphBLAS uses modular arithmetic instead. @@ -804,7 +781,7 @@ % matrices, since it doesn't support sparse integer matrices. %% -% (4) Faster methods: +% (3) Faster methods: % % Most methods in this MATLAB interface are based on efficient parallel C % functions in GraphBLAS itself, and are typically as fast or faster than @@ -817,9 +794,7 @@ % illustrated below in the next example. % % Other methods that will be faster in the future include bandwidth, -% istriu, istril, eps, ceil, floor, round, fix, isfinite, isinf, isnan, -% spfun, and A.^B. These methods are currently implemented in -% m-files, not in efficient parallel C functions. +% istriu, istril, isdiag, reshape, issymmetric, and ishermitian. %% % Here is an example that illustrates the performance of C = [A B] @@ -845,22 +820,22 @@ end %% -% (5) Linear indexing: +% (4) Linear indexing: % % If A is an m-by-n 2D MATLAB matrix, with n > 1, A(:) is a column vector % of length m*n. The index operation A(i) accesses the ith entry in the % vector A(:). This is called linear indexing in MATLAB. It is not yet % available for GraphBLAS matrices in this MATLAB interface to GraphBLAS, -% but it could be added in the future. +% but will be added in the future. %% -% (6) Implicit singleton dimension expansion +% (5) Implicit singleton dimension expansion % % In MATLAB C=A+B where A is m-by-n and B is a 1-by-n row vector % implicitly expands B to a matrix, computing C(i,j)=A(i,j)+B(j). This % implicit expansion is not yet suported in GraphBLAS with C=A+B. % However, it can be done with C = GrB.mxm ('+.+', A, diag(GrB(B))). -% That's an nice example of the power of semirings, but it's not +% That's a nice example of the power of semirings, but it's not % immediately obvious, and not as clear a syntax as C=A+B. The % GraphBLAS/@GrB/dnn.m function uses this 'plus.plus' semiring to % apply the bias to each neuron. @@ -871,13 +846,36 @@ C2 = GrB.mxm ('+.+', A, diag (GrB (B))) err = norm (C1-C2,1) +%% +% (6) Performance issues +% +% The GrB matrix is a MATLAB object, and there are some cases where +% performance issues can arise. Extracting the contents of a MATLAB +% object (G.field) takes much more time than for a MATLAB struct with +% the same syntax, and building an object has similar issues. The +% difference is small, and it does not affect large problems. But if +% you have many calls to GrB operations with a small amount of work, +% then the time can be dominated by the MATLAB object-oriented overhead. + +A = rand (3,4) ; +G = GrB (A) ; +tic +for k = 1:100000 + [m, n] = size (A) ; +end +toc +tic +for k = 1:100000 + [m, n] = size (G) ; +end +toc + %% GraphBLAS operations % In addition to the overloaded operators (such as C=A*B) and overloaded % functions (such as L=tril(A)), GraphBLAS also has methods of the form -% GrB.method, listed on the next page. Most of them take an optional -% input matrix Cin, which is the initial value of the matrix C for the -% expression below, an optional mask matrix M, and an optional -% accumulator operator. +% GrB.method. Most of them take an optional input matrix Cin, which is +% the initial value of the matrix C for the expression below, an optional +% mask matrix M, and an optional accumulator operator. % % C<#M,replace> = accum (C, T) % @@ -888,245 +886,12 @@ % Z=accum(C,T). The matrix T is the result of some operation, such as % T=A*B for GrB.mxm, or T=op(A,B) for GrB.eadd. % -% A summary of these GrB.methods is on the next pages. - -%% Methods for the GrB class: -% -% These methods operate on GraphBLAS matrices only, and they overload -% the existing MATLAB functions of the same name. -% -% C = GrB (...) construct a GraphBLAS matrix -% C = sparse (G) makes a copy of a GrB matrix -% C = full (G, ...) adds explicit zeros or id values to a GrB matrix -% C = double (G) cast GrB matrix to MATLAB sparse double matrix -% C = logical (G) cast GrB matrix to MATLAB sparse logical matrix -% C = complex (G) cast GrB matrix to MATLAB sparse complex -% C = single (G) cast GrB matrix to MATLAB full single matrix -% C = int8 (G) cast GrB matrix to MATLAB full int8 matrix -% C = int16 (G) cast GrB matrix to MATLAB full int16 matrix -% C = int32 (G) cast GrB matrix to MATLAB full int32 matrix -% C = int64 (G) cast GrB matrix to MATLAB full int64 matrix -% C = uint8 (G) cast GrB matrix to MATLAB full uint8 matrix -% C = uint16 (G) cast GrB matrix to MATLAB full uint16 matrix -% C = uint32 (G) cast GrB matrix to MATLAB full uint32 matrix -% C = uint64 (G) cast GrB matrix to MATLAB full uint64 matrix -% C = cast (G,...) cast GrB matrix to MATLAB matrix (as above) - -%% -% X = nonzeros (G) extract all entries from a GrB matrix -% [I,J,X] = find (G) extract all entries from a GrB matrix -% C = spones (G) return pattern of GrB matrix -% disp (G, level) display a GrB matrix G -% display (G) display a GrB matrix G; same as disp(G,2) -% mn = numel (G) m*n for an m-by-n GrB matrix G -% e = nnz (G) number of entries in a GrB matrix G -% e = nzmax (G) number of entries in a GrB matrix G -% [m n] = size (G) size of a GrB matrix G -% n = length (G) length of a GrB vector -% s = isempty (G) true if any dimension of G is zero -% s = issparse (G) true for any GrB matrix G -% s = ismatrix (G) true for any GrB matrix G -% s = isvector (G) true if m=1 or n=1, for an m-by-n GrB matrix G -% s = iscolumn (G) true if n=1, for an m-by-n GrB matrix G -% s = isrow (G) true if m=1, for an m-by-n GrB matrix G -% s = isscalar (G) true if G is a 1-by-1 GrB matrix -% s = isnumeric (G) true for any GrB matrix G (even logical) -% s = isfloat (G) true if GrB matrix is double, single, complex -% s = isreal (G) true if GrB matrix is not complex -% s = isinteger (G) true if GrB matrix is int8, int16, ..., uint64 -% s = islogical (G) true if GrB matrix is logical -% s = isa (G, classname) check if a GrB matrix is of a specific class - -%% -% C = diag (G,k) diagonal matrices and diagonals of GrB matrix G -% L = tril (G,k) lower triangular part of GrB matrix G -% U = triu (G,k) upper triangular part of GrB matrix G -% C = kron (A,B) Kronecker product -% C = repmat (G, ...) replicate and tile a GraphBLAS matrix -% C = reshape (G, ...) reshape a GraphBLAS matrix -% C = abs (G) absolute value -% C = sign (G) signum function -% s = istril (G) true if G is lower triangular -% s = istriu (G) true if G is upper triangular -% s = isbanded (G,...) true if G is banded -% s = isdiag (G) true if G is diagonal -% s = ishermitian (G) true if G is Hermitian -% s = issymmetric (G) true if G is symmetric -% [lo,hi] = bandwidth (G) determine the lower & upper bandwidth of G -% C = sum (G, option) reduce via sum, to vector or scalar -% C = prod (G, option) reduce via product, to vector or scalar -% s = norm (G, kind) 1-norm or inf-norm of a GrB matrix -% C = max (G, ...) reduce via max, to vector or scalar -% C = min (G, ...) reduce via min, to vector or scalar -% C = any (G, ...) reduce via '|', to vector or scalar -% C = all (G, ...) reduce via '&', to vector or scalar - -%% -% C = sqrt (G) element-wise square root -% C = eps (G) floating-point spacing -% C = ceil (G) round towards infinity -% C = floor (G) round towards -infinity -% C = round (G) round towards nearest -% C = fix (G) round towards zero -% C = isfinite (G) test if finite -% C = isinf (G) test if infinite -% C = isnan (G) test if NaN -% C = spfun (fun, G) evaluate a function on the entries of G -% p = amd (G) approximate minimum degree ordering -% p = colamd (G) column approximate minimum degree ordering -% p = symamd (G) approximate minimum degree ordering -% p = symrcm (G) reverse Cuthill-McKee ordering -% [...] = dmperm (G) Dulmage-Mendelsohn permutation -% parent = etree (G) elimination tree -% C = conj (G) complex conjugate -% C = real (G) real part of a complex GraphBLAS matrix -% [V, ...] = eig (G,...) eigenvalues and eigenvectors -% assert (G) generate an error if G is false -% C = zeros (...,'like',G) all-zero matrix, same type as G -% C = false (...,'like',G) all-false logical matrix -% C = ones (...,'like',G) matrix with all ones, same type as G - -%% Operator overloading: -% -% C = plus (A, B) C = A + B -% C = minus (A, B) C = A - B -% C = uminus (G) C = -G -% C = uplus (G) C = +G -% C = times (A, B) C = A .* B -% C = mtimes (A, B) C = A * B -% C = rdivide (A, B) C = A ./ B -% C = ldivide (A, B) C = A .\ B -% C = mrdivide (A, B) C = A / B -% C = mldivide (A, B) C = A \ B -% C = power (A, B) C = A .^ B -% C = mpower (A, B) C = A ^ B -% C = lt (A, B) C = A < B -% C = gt (A, B) C = A > B -% C = le (A, B) C = A <= B -% C = ge (A, B) C = A >= B -% C = ne (A, B) C = A ~= B -% C = eq (A, B) C = A == B -% C = and (A, B) C = A & B -% C = or (A, B) C = A | B -% C = not (G) C = ~G -% C = ctranspose (G) C = G' -% C = transpose (G) C = G.' -% C = horzcat (A, B) C = [A , B] -% C = vertcat (A, B) C = [A ; B] -% C = subsref (A, I, J) C = A (I,J) or C = A (M) -% C = subsasgn (A, I, J) C (I,J) = A -% index = end (A, k, n) for object indexing, A(1:end,1:end) - -%% Static Methods: -% -% The Static Methods for the GrB class can be used on input matrices of -% any kind: GraphBLAS sparse matrices, MATLAB sparse matrices, or -% MATLAB dense matrices, in any combination. The output matrix Cout is -% a GraphBLAS matrix, by default, but can be optionally returned as a -% MATLAB sparse or dense matrix. The static methods divide into two -% categories: those that perform basic functions, and the GraphBLAS -% operations that use the mask/accum. - -%% GraphBLAS basic functions: -% -% GrB.clear clear GraphBLAS workspace and settings -% GrB.descriptorinfo (d) list properties of a descriptor -% GrB.unopinfo (op, type) list properties of a unary operator -% GrB.binopinfo (op, type) list properties of a binary operator -% GrB.monoidinfo (op, type) list properties of a monoid -% GrB.semiringinfo (s, type) list properties of a semiring -% t = GrB.threads (t) set/get # of threads to use in GraphBLAS -% c = GrB.chunk (c) set/get chunk size to use in GraphBLAS -% b = GrB.burble (b) set/get burble (diagnostic output) -% result = GrB.entries (G,...) count or query entries in a matrix -% result = GrB.nonz (G,...) count or query nonzeros in a matrix -% C = GrB.prune (A, id) prune entries equal to id -% C = GrB.offdiag (A) prune diagonal entries -% s = GrB.isfull (A) true if all entries present -% [C,I,J] = GrB.compact (A,id) remove empty rows and columns -% G = GrB.empty (m, n) return an empty GraphBLAS matrix -% s = GrB.type (A) get the type of a MATLAB or GrB matrix A -% s = GrB.issigned (type) true if type is signed -% f = GrB.format (f) set/get matrix format to use in GraphBLAS -% s = GrB.isbyrow (A) true if format f A is 'by row' -% s = GrB.isbycol (A) true if format f A is 'by col' -% C = GrB.expand (scalar, A) expand a scalar (C = scalar*spones(A)) -% C = GrB.eye identity matrix of any type -% C = GrB.speye identity matrix (of type 'double') -% C = GrB.build (I, J, X, m, n, dup, type, desc) -% build a GrB matrix from list of entries -% [I,J,X] = GrB.extracttuples (A, desc) -% extract all entries from a matrix -% s = GrB.normdiff (A, B, kind) norm (A-B,kind) - -%% GraphBLAS operations with Cout, mask M, and accum. -% -% Cout = GrB.mxm (Cin, M, accum, semiring, A, B, desc) -% sparse matrix-matrix multiplication over a semiring -% Cout = GrB.select (Cin, M, accum, op, A, b, desc) -% select a subset of entries from a matrix -% Cout = GrB.assign (Cin, M, accum, A, I, J, desc) -% sparse matrix assignment, such as C(I,J)=A -% Cout = GrB.subassign (Cin, M, accum, A, I, J, desc) -% sparse matrix assignment, such as C(I,J)=A -% Cout = GrB.vreduce (Cin, M, accum, op, A, desc) -% reduce a matrix to a vector -% Cout = GrB.reduce (Cin, accum, op, A, desc) -% reduce a matrix to a scalar -% Cout = GrB.kronecker (Cin, M, accum, op, A, B, desc) -% Kronecker product -% Cout = GrB.trans (Cin, M, accum, A, desc) -% transpose a matrix -% Cout = GrB.eadd (Cin, M, accum, op, A, B, desc) -% element-wise addition -% Cout = GrB.emult (Cin, M, accum, op, A, B, desc) -% element-wise multiplication -% Cout = GrB.apply (Cin, M, accum, op, A, desc) -% apply a unary operator -% Cout = GrB.extract (Cin, M, accum, A, I, J, desc) -% extract submatrix, like C=A(I,J) in MATLAB -% -%% -% GraphBLAS operations (with Cout, Cin arguments) take the following form: -% -% C<#M,replace> = accum (C, operation (A or A', B or B')) -% -% C is both an input and output matrix. In this MATLAB interface to -% GraphBLAS, it is split into Cin (the value of C on input) and Cout -% (the value of C on output). M is the optional mask matrix, and #M is -% either M or !M depending on whether or not the mask is complemented -% via the desc.mask option. The replace option is determined by -% desc.out; if present, C is cleared after it is used in the accum -% operation but before the final assignment. A and/or B may optionally -% be transposed via the descriptor fields desc.in0 and desc.in1, -% respectively. To select the format of Cout, use desc.format. See -% GrB.descriptorinfo for more details. -% -% accum is optional; if not is not present, then the operation becomes -% C<...> = operation(A,B). Otherwise, C = C + operation(A,B) is -% computed where '+' is the accum operator. It acts like a sparse -% matrix addition (see GrB.eadd), in terms of the structure of the -% result C, but any binary operator can be used. -% -% The mask M acts like MATLAB logical indexing. If M(i,j)=1 then -% C(i,j) can be modified; if zero, it cannot be modified by the -% operation. - -%% Static Methods for graph algorithms: -% -% r = GrB.pagerank (A, opts) ; % PageRank of a matrix -% C = GrB.ktruss (A, k, check) ; % k-truss -% s = GrB.tricount (A, check) ; % triangle count -% L = GrB.laplacian (A, type, check) ; % Laplacian graph -% C = GrB.incidence (A, ...) ; % incidence matrix -% [v, parent] = GrB.bfs (A, s, ...) ; % breadth-first search -% iset = GrB.mis (A, check) ; % maximal independent set -% Y = GrB.dnn (W, bias, Y0) ; % deep neural network +% For a complete list of GraphBLAS overloaded operators and methods, type: % -% More graph algorithms will be added in the future. +% help GrB % % Thanks for watching! % % Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis -% See also sparse, doc sparse, and https://twitter.com/DocSparse +% See also doc sparse and https://twitter.com/DocSparse diff --git a/GraphBLAS/demo/html/DGX_Station/README.txt b/GraphBLAS/demo/html/DGX_Station/README.txt index 44b74cbad7..c0021ac0d0 100644 --- a/GraphBLAS/demo/html/DGX_Station/README.txt +++ b/GraphBLAS/demo/html/DGX_Station/README.txt @@ -9,7 +9,3 @@ The CPU has 20 hardware cores, and 20 threads were used A GPU-accelerated GraphBLAS is in progress, but this test did not use any of the four Volta V100 GPUs. -v310: output from GraphBLAS v3.1.0 -v312: output from GraphBLAS v3.1.2 (draft, Nov 15, 2019) -v320: output from GraphBLAS v3.2.0 (draft, Feb 19, 2020) - diff --git a/GraphBLAS/demo/html/DGX_Station/graphblas_demo.html b/GraphBLAS/demo/html/DGX_Station/graphblas_demo.html new file mode 100644 index 0000000000..f0d6766e2b --- /dev/null +++ b/GraphBLAS/demo/html/DGX_Station/graphblas_demo.html @@ -0,0 +1,2406 @@ + + + + + GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS is a library for creating graph algorithms based on sparse linear algebraic operations over semirings. Visit http://graphblas.org for more details and resources. See also the SuiteSparse:GraphBLAS User Guide in this package.

SuiteSparse:GraphBLAS, (c) 2017-2020, Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis

Contents

GraphBLAS: faster and more general sparse matrices for MATLAB

GraphBLAS is not only useful for creating graph algorithms; it also supports a wide range of sparse matrix data types and operations. MATLAB can compute C=A*B with just two semirings: 'plus.times.double' and 'plus.times.complex' for complex matrices. GraphBLAS has 1,473 unique built-in semirings, such as 'max.plus' (https://en.wikipedia.org/wiki/Tropical_semiring). These semirings can be used to construct a wide variety of graph algorithms, based on operations on sparse adjacency matrices.

MATLAB and GraphBLAS both provide sparse matrices of type double, logical, and double complex. GraphBLAS adds sparse matrices of type: single, int8, int16, int32, int64, uint8, uint16, uint32, uint64, and single complex (with MATLAB matrices, these types can only be held in full matrices).

clear
+GrB.clear
+format compact
+rng ('default') ;
+X = 100 * rand (2) ;
+G = GrB (X)              % GraphBLAS copy of a matrix X, same type
+
+G =
+
+  2x2 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)    81.4724
+    (2,1)    90.5792
+    (1,2)    12.6987
+    (2,2)    91.3376
+
+

Sparse integer matrices

Here's an int8 version of the same matrix:

S = int8 (G)            % convert G to a full MATLAB int8 matrix
+G = GrB (X, 'int8')      % a GraphBLAS sparse int8 matrix
+
S =
+  2x2 int8 matrix
+   81   13
+   91   91
+
+G =
+
+  2x2 GraphBLAS int8_t matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)   81
+    (2,1)   91
+    (1,2)   13
+    (2,2)   91
+
+

Sparse single-precision matrices

Matrix operations in GraphBLAS are typically as fast, or faster than MATLAB. Here's an unfair comparison: computing X^2 with MATLAB in double precision and with GraphBLAS in single precision. You would naturally expect GraphBLAS to be faster.

Please wait ...

n = 1e5 ;
+X = spdiags (rand (n, 201), -100:100, n, n) ;
+G = GrB (X, 'single') ;
+tic
+G2 = G^2 ;
+gb_time = toc ;
+tic
+X2 = X^2 ;
+matlab_time = toc ;
+fprintf ('\nGraphBLAS time: %g sec (in single)\n', gb_time) ;
+fprintf ('MATLAB time:    %g sec (in double)\n', matlab_time) ;
+fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
+    matlab_time / gb_time) ;
+
+GraphBLAS time: 0.511561 sec (in single)
+MATLAB time:    9.62246 sec (in double)
+Speedup of GraphBLAS over MATLAB: 18.81
+

Mixing MATLAB and GraphBLAS matrices

The error in the last computation is about eps('single') since GraphBLAS did its computation in single precision, while MATLAB used double precision. MATLAB and GraphBLAS matrices can be easily combined, as in X2-G2. The sparse single precision matrices take less memory space.

err = norm (X2 - G2, 1) / norm (X2,1)
+eps ('single')
+whos G G2 X X2
+
err =
+   1.5049e-07
+ans =
+  single
+  1.1921e-07
+  Name           Size                    Bytes  Class     Attributes
+
+  G         100000x100000            241879764  GrB                 
+  G2        100000x100000            481518564  GrB                 
+  X         100000x100000            322238408  double    sparse    
+  X2        100000x100000            641756808  double    sparse    
+
+

Faster matrix operations

But even with standard double precision sparse matrices, GraphBLAS is typically faster than the built-in MATLAB methods. Here's a fair comparison:

G = GrB (X) ;
+tic
+G2 = G^2 ;
+gb_time = toc ;
+err = norm (X2 - G2, 1) / norm (X2,1)
+fprintf ('\nGraphBLAS time: %g sec (in double)\n', gb_time) ;
+fprintf ('MATLAB time:    %g sec (in double)\n', matlab_time) ;
+fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
+    matlab_time / gb_time) ;
+
err =
+     0
+
+GraphBLAS time: 0.585372 sec (in double)
+MATLAB time:    9.62246 sec (in double)
+Speedup of GraphBLAS over MATLAB: 16.4382
+

A wide range of semirings

MATLAB can only compute C=A*B using the standard '+.*.double' and '+.*.complex' semirings. A semiring is defined in terms of a string, 'add.mult.type', where 'add' is a monoid that takes the place of the additive operator, 'mult' is the multiplicative operator, and 'type' is the data type for the two inputs to the mult operator.

In the standard semiring, C=A*B is defined as:

C(i,j) = sum (A(i,:).' .* B(:,j))
+

using 'plus' as the monoid and 'times' as the multiplicative operator. But in a more general semiring, 'sum' can be any monoid, which is an associative and commutative operator that has an identity value. For example, in the 'max.plus' tropical algebra, C(i,j) for C=A*B is defined as:

C(i,j) = max (A(i,:).' + B(:,j))
+

This can be computed in GraphBLAS with:

C = GrB.mxm ('max.+', A, B)
+
n = 3 ;
+A = rand (n) ;
+B = rand (n) ;
+C = zeros (n) ;
+for i = 1:n
+    for j = 1:n
+        C(i,j) = max (A (i,:).' + B (:,j)) ;
+    end
+end
+C2 = GrB.mxm ('max.+', A, B) ;
+fprintf ('\nerr = norm (C-C2,1) = %g\n', norm (C-C2,1)) ;
+
+err = norm (C-C2,1) = 0
+

The max.plus tropical semiring

Here are details of the "max.plus" tropical semiring. The identity value is -inf since max(x,-inf) = max (-inf,x) = x for any x. The identity for the conventional "plus.times" semiring is zero, since x+0 = 0+x = x for any x.

GrB.semiringinfo ('max.+.double') ;
+
+    GraphBLAS Semiring: max.+.double (built-in)
+    GraphBLAS Monoid: semiring->add (built-in)
+    GraphBLAS BinaryOp: monoid->op (built-in) z=max(x,y)
+    GraphBLAS type: ztype double size: 8
+    GraphBLAS type: xtype double size: 8
+    GraphBLAS type: ytype double size: 8
+    identity: [    -Inf ] terminal: [    Inf ]
+
+    GraphBLAS BinaryOp: semiring->multiply (built-in) z=plus(x,y)
+    GraphBLAS type: ztype double size: 8
+    GraphBLAS type: xtype double size: 8
+    GraphBLAS type: ytype double size: 8
+

A boolean semiring

MATLAB cannot multiply two logical matrices. MATLAB R2019a converts them to double and uses the conventional +.*.double semiring instead. In GraphBLAS, this is the common Boolean 'or.and.logical' semiring, which is widely used in linear algebraic graph algorithms.

GrB.semiringinfo ('|.&.logical') ;
+
+    GraphBLAS Semiring: |.&.logical (built-in)
+    GraphBLAS Monoid: semiring->add (built-in)
+    GraphBLAS BinaryOp: monoid->op (built-in) z=or(x,y)
+    GraphBLAS type: ztype bool size: 1
+    GraphBLAS type: xtype bool size: 1
+    GraphBLAS type: ytype bool size: 1
+    identity: [   0 ] terminal: [   1 ]
+
+    GraphBLAS BinaryOp: semiring->multiply (built-in) z=and(x,y)
+    GraphBLAS type: ztype bool size: 1
+    GraphBLAS type: xtype bool size: 1
+    GraphBLAS type: ytype bool size: 1
+
clear
+A = sparse (rand (3) > 0.5)
+B = sparse (rand (3) > 0.2)
+
A =
+  3x3 sparse logical array
+   (2,1)      1
+   (2,2)      1
+   (3,2)      1
+   (1,3)      1
+B =
+  3x3 sparse logical array
+   (1,1)      1
+   (2,1)      1
+   (3,1)      1
+   (1,2)      1
+   (2,2)      1
+   (3,2)      1
+   (1,3)      1
+   (2,3)      1
+   (3,3)      1
+
try
+    % MATLAB R2019a does this by casting A and B to double
+    C1 = A*B
+catch
+    % MATLAB R2018a throws an error
+    fprintf ('MATLAB R2019a required for C=A*B with logical\n') ;
+    fprintf ('matrices.  Explicitly converting to double:\n') ;
+    C1 = double (A) * double (B)
+end
+C2 = GrB (A) * GrB (B)
+
MATLAB R2019a required for C=A*B with logical
+matrices.  Explicitly converting to double:
+C1 =
+   (1,1)        1
+   (2,1)        2
+   (3,1)        1
+   (1,2)        1
+   (2,2)        2
+   (3,2)        1
+   (1,3)        1
+   (2,3)        2
+   (3,3)        1
+
+C2 =
+
+  3x3 GraphBLAS bool matrix, sparse by col:
+  9 nonzeros, 9 entries
+
+    (1,1)   1
+    (2,1)   1
+    (3,1)   1
+    (1,2)   1
+    (2,2)   1
+    (3,2)   1
+    (1,3)   1
+    (2,3)   1
+    (3,3)   1
+
+

Note that C1 is a MATLAB sparse double matrix, and contains non-binary values. C2 is a GraphBLAS logical matrix.

whos
+GrB.type (C2)
+
  Name      Size            Bytes  Class      Attributes
+
+  A         3x3                68  logical    sparse    
+  B         3x3               113  logical    sparse    
+  C1        3x3               176  double     sparse    
+  C2        3x3              1071  GrB                  
+
+ans =
+    'logical'
+

GraphBLAS operators, monoids, and semirings

The C interface for SuiteSparse:GraphBLAS allows for arbitrary types and operators to be constructed. However, the MATLAB interface to SuiteSparse:GraphBLAS is restricted to pre-defined types and operators: a mere 13 types, 204 unary operators, 385 binary operators, 77 monoids, 16 select operators, and 2,438 semirings (1,473 of which are unique, since some binary operators are equivalent: 'min.logical' and '&.logical' are the same thing, for example).

That gives you a lot of tools to create all kinds of interesting graph algorithms. For example:

GrB.bfs    % breadth-first search
+GrB.dnn    % sparse deep neural network (http://graphchallenge.org)
+GrB.mis    % maximal independent set
+

See 'help GrB.binopinfo' for a list of the binary operators, and 'help GrB.monoidinfo' for the ones that can be used as the additive monoid in a semiring. 'help GrB.unopinfo' lists the unary operators.

help GrB.binopinfo
+
 GRB.BINOPINFO list the details of a GraphBLAS binary operator.
+ 
+    GrB.binopinfo
+    GrB.binopinfo (op)
+    GrB.binopinfo (op, optype)
+ 
+  Binary operators are defined by a string of the form 'op.optype', or
+  just 'op', where the optype is inferred from the operands.  Valid
+  optypes are 'logical', 'int8', 'int16', 'int32', 'int64', 'uint8',
+  'uint16', 'uint32', 'uint64', 'single', 'double', 'single complex',
+  'double complex' (the latter can be written as simply 'complex').
+ 
+  For GrB.binopinfo (op), the op must be a string of the form 'op.optype',
+  where 'op' is listed below.  The second usage allows the optype to be
+  omitted from the first argument, as just 'op'.  This is valid for all
+  GraphBLAS operations, since the optype can be determined from the
+  operands (see Typecasting, below).  However, GrB.binopinfo does not have
+  any operands and thus the optype must be provided, either in the op as
+  GrB.binopinfo ('+.double'), or in the second argument as
+  GrB.binopinfo ('+', 'double').
+ 
+  The 6 comparator operators come in two flavors.  For the is* operators,
+  the result has the same type as the inputs, x and y, with 1 for true and
+  0 for false.  For example isgt.double (pi, 3.0) is the double value 1.0.
+  For the second set of 6 operators (eq, ne, gt, lt, ge, le), the result
+  is always logical (true or false).  In a semiring, the optype of the add
+  monoid must exactly match the type of the output of the multiply
+  operator, and thus 'plus.iseq.double' is valid (counting how many terms
+  are equal).  The 'plus.eq.double' semiring is valid, but not the same
+  semiring since the 'plus' of 'plus.eq.double' has a logical type and is
+  thus equivalent to 'or.eq.double'.   The 'or.eq' is true if any terms
+  are equal and false otherwise (it does not count the number of terms
+  that are equal).
+ 
+  The following binary operators are available for most types.  Many have
+  equivalent synonyms, so that '1st' and 'first' both define the
+  first(x,y) = x operator.
+ 
+    operator name(s) f(x,y)         |   operator names(s) f(x,y)
+    ---------------- ------         |   ----------------- ------
+    1st first        x              |   iseq             x == y
+    2nd second       y              |   isne             x ~= y
+    min              min(x,y)       |   isgt             x > y
+    max              max(x,y)       |   islt             x < y
+    +   plus         x+y            |   isge             x >= y
+    -   minus        x-y            |   isle             x <= y
+    rminus           y-x            |   ==  eq           x == y
+    *   times        x*y            |   ~=  ne           x ~= y
+    /   div          x/y            |   >   gt           x > y
+    \   rdiv         y/x            |   <   lt           x < y
+    |   || or  lor   x | y          |   >=  ge           x >= y
+    &   && and land  x & y          |   <=  le           x <= y
+    xor lxor         xor(x,y)       |   .^  pow          x .^ y
+    pair             1              |   any              pick x or y
+ 
+  Comparators (*lt, *gt, *le, *ge) and min/max are not available for
+  complex types.
+ 
+  All of the above operators are defined for logical operands, but many
+  are redundant. 'min.logical' is the same as 'and.logical', for example.
+  Most of the logical operators have aliases: ('lor', 'or', '|') are the
+  same, as are ('lxnor', 'xnor', 'eq', '==') for logical types.
+ 
+  The three logical operators, lor, land, and lxor, can be used with any
+  real types.  z = lor.double (x,y) tests the condition (x~=0) || (y~=0),
+  and returns the double value 1.0 if true, or 0.0 if false.
+ 
+  The following operators are avaiable for single and double (real); their
+  definitions are identical to the ANSI C11 versions of these functions:
+  atan2, hypot, fmod, remainder, copysign, ldxep (also called 'pow2').
+  All produce the same type as the input, on output.
+ 
+  z = cmplx(x,y) can be computed for x and y as single and double; z is
+  single complex or double complex, respectively.
+ 
+  The following bitwise operators are available for any signed or
+  unsigned integer types:  bitor, bitand, bitxor, bitxnor, bitget, bitset,
+  bitclr, and bitshift.
+ 
+  Typecasting:  If the optype is omitted from the string (for example,
+  GrB.eadd (A, '+', B) or simply C = A+B), then the optype is inferred
+  from the type of A and B.  See 'help GrB.optype' for details.
+ 
+  Example:
+ 
+    % valid binary operators
+    GrB.binopinfo ('+.double') ;    % also a valid unary operator
+    GrB.binopinfo ('1st.int32') ;
+    GrB.binopinfo ('cmplx.single') ;
+    GrB.binopinfo ('pow2.double') ; % also a valid unary operator
+    GrB.unopinfo  ('pow2.double') ;
+ 
+    % invalid binary operator (an error; this is a unary op):
+    GrB.binopinfo ('abs.double') ;
+ 
+  See also GrB.descriptorinfo, GrB.monoidinfo, GrB.selectopinfo,
+  GrB.semiringinfo, GrB.unopinfo, GrB.optype.
+
+
help GrB.monoidinfo
+
 GRB.MONOIDINFO list the details of a GraphBLAS monoid.
+ 
+    GrB.monoidinfo
+    GrB.monoidinfo (monoid)
+    GrB.monoidinfo (monoid, type)
+ 
+  For GrB.monoidinfo(op), the op must be a string of the form 'op.type',
+  where 'op' is listed below.  The second usage allows the type to be
+  omitted from the first argument, as just 'op'.  This is valid for all
+  GraphBLAS operations, since the type defaults to the type of the input
+  matrices.  However, GrB.monoidinfo does not have a default type and thus
+  one must be provided, either in the op as GrB.monoidinfo ('+.double'), or
+  in the second argument, GrB.monoidinfo ('+', 'double').
+ 
+  A monoid is any binary operator z=f(x,y) that is commutative and
+  associative, with an identity value o so that f(x,o)=f(o,x)=o.  The types
+  of z, x, and y must all be identical.  For example, the plus.double
+  operator is f(x,y)=x+y, with zero as the identity value (x+0 = 0+x = x).
+  The times monoid has an identity value of 1 (since x*1 = 1*x = x).  The
+  identity of min.double is -inf.
+ 
+  The valid monoids for real non-logical types are:
+        '+', '*', 'max', 'min', 'any'
+  For the 'logical' type:
+        '|', '&', 'xor', 'eq', 'any'
+  For complex types:
+        '+', '*', 'any'
+  For integer types (signed and unsigned):
+        'bitor', 'bitand', 'bitxor', 'bitxnor'
+ 
+  Some monoids have synonyms; see 'help GrB.binopinfo' for details.
+ 
+  Example:
+ 
+    % valid monoids
+    GrB.monoidinfo ('+.double') ;
+    GrB.monoidinfo ('*.int32') ;
+    GrB.monoidinfo ('min.double') ;
+ 
+    % invalid monoids
+    GrB.monoidinfo ('1st.int32') ;
+    GrB.monoidinfo ('abs.double') ;
+    GrB.monoidinfo ('min.complex') ;
+ 
+  See also GrB.binopinfo, GrB.descriptorinfo, GrB.selectopinfo,
+  GrB.semiringinfo, GrB.unopinfo.
+
+
help GrB.unopinfo
+
 GRB.UNOPINFO list the details of a GraphBLAS unary operator.
+ 
+    GrB.unopinfo
+    GrB.unopinfo (op)
+    GrB.unopinfo (op, type)
+ 
+  For GrB.unopinfo(op), the op must be a string of the form 'op.type',
+  where 'op' is listed below.  The second usage allows the type to be
+  omitted from the first argument, as just 'op'.  This is valid for all
+  GraphBLAS operations, since the type defaults to the type of the input
+  matrix.  However, GrB.unopinfo does not have a default type and thus one
+  must be provided, either in the op as GrB.unopinfo ('abs.double'), or in
+  the second argument, GrB.unopinfo ('abs', 'double').
+ 
+  The functions z=f(x) are listed below.  Unless otherwise specified,
+  z and x have the same type.  Some functions have synonyms, as listed.
+ 
+  For all 13 types:
+    identity    z = x       also '+', 'uplus'
+    ainv        z = -x      additive inverse, also '-', 'negate', 'uminus'
+    minv        z = 1/x     multiplicative inverse
+    one         z = 1       does not depend on x, also '1'
+    abs         z = |x|     'abs.complex' returns a real result
+ 
+  For all 11 real types:
+    lnot        z = ~(x ~= 0)   logical negation (z is 1 or 0, with the
+                                same type as x), also '~', 'not'.
+ 
+  For 4 floating-point types (real & complex)x(single & double):
+    sqrt        z = sqrt (x)    square root
+    log         z = log (x)     base-e logarithm
+    log2        z = log2 (x)    base-2 logarithm
+    log10       z = log10 (x)   base-10 logarithm
+    log1p       z = log1p (x)   log (x-1), base-e
+    exp         z = exp (x)     base-e exponential, e^x
+    pow2        z = pow2 (x)    base-2 exponential, 2^x
+    expm1       z = exp1m (x)   e^x-1
+    sin         z = sin (x)     sine
+    cos         z = cos (x)     cosine
+    tan         z = tan (x)     tangent
+    acos        z = acos (x)    arc cosine
+    asin        z = asin (x)    arc sine
+    atan        z = atan (x)    arc tangent
+    sinh        z = sinh (x)    hyperbolic sine
+    cosh        z = cosh (x)    hyperbolic cosine
+    tanh        z = tanh (x)    hyperbolic tangent
+    asinh       z = asinh (x)   inverse hyperbolic sine
+    acosh       z = acosh (x)   inverse hyperbolic cosine
+    atanh       z = atanh (x)   inverse hyperbolic tangent
+    signum      z = signum (x)  signum function, also 'sign'
+    ceil        z = ceil (x)    ceiling
+    floor       z = floor (x)   floor
+    round       z = round (x)   round to nearest
+    trunc       z = trunc (x)   truncate, also 'fix'
+ 
+  For 'single complex' and 'double complex' only:
+    creal       z = real (x)    real part of x (z is real), also 'real'
+    cimag       z = imag (x)    imag. part of x (z is real), also 'imag'
+    carg        z = carg (x)    phase angle (z is real), also 'angle'
+    conj        z = conj (x)    complex conjugate (z is complex)
+ 
+  For all 4 floating-point types (result is logical):
+    isinf       z = isinf (x)       true if x is +Inf or -Inf
+    isnan       z = isnan (x)       true if x is NaN
+    isfinite    z = isfinite (x)    true if x is finite
+ 
+  For single and double (result same type as input):
+    lgamma      z = lgamma (x)  log of gamma function, also 'gammaln'
+    tgamma      z = tgamma (x)  gamma function, also 'gamma'
+    erf         z = erf (x)     error function
+    erfc        z = erfc (x)    complementary error function
+    frexpx      z = frexpx (x)  mantissa from ANSI C11 frexp function
+    frexpe      z = frexpe (x)  exponent from ANSI C11 frexp function
+                                The MATLAB [f,e]=log2(x) returns
+                                f = frexpx (x) and e = frexpe (x).
+ 
+  For integer types only (result is same type as input):
+    bitcmp      z = ~(x)        bitwise complement, also 'bitnot'
+ 
+  Example:
+ 
+    % valid unary operators
+    GrB.unopinfo ('+.double') ;     % also a valid binary operator
+    GrB.unopinfo ('abs.double') ;
+    GrB.unopinfo ('not.int32') ;
+    GrB.unopinfo ('pow2.double') ;  % also a valid binary operator
+    GrB.binopinfo ('pow2.double') ;
+ 
+    % invalid unary operator (generates an error; this is a binary op):
+    GrB.unopinfo ('*.double') ;
+ 
+  See also GrB.binopinfo, GrB.descriptorinfo, GrB.monoidinfo,
+  GrB.selectopinfo, GrB.semiringinfo.
+
+

Element-wise operations

Binary operators can be used in element-wise matrix operations, like C=A+B and C=A.*B. For the matrix addition C=A+B, the pattern of C is the set union of A and B, and the '+' operator is applied for entries in the intersection. Entries in A but not B, or in B but not A, are assigned to C without using the operator. The '+' operator is used for C=A+B but any operator can be used with GrB.eadd.

A = GrB (sprand (3, 3, 0.5)) ;
+B = GrB (sprand (3, 3, 0.5)) ;
+C1 = A + B
+C2 = GrB.eadd ('+', A, B)
+err = norm (C1-C2,1)
+
+C1 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  7 nonzeros, 7 entries
+
+    (1,1)    0.666139
+    (3,1)    0.735859
+    (1,2)    1.47841
+    (2,2)    0.146938
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+
+C2 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  7 nonzeros, 7 entries
+
+    (1,1)    0.666139
+    (3,1)    0.735859
+    (1,2)    1.47841
+    (2,2)    0.146938
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+err =
+     0
+

Subtracting two matrices

A-B and GrB.eadd ('-', A, B) are not the same thing, since the '-' operator is not applied to an entry that is in B but not A.

C1 = A-B
+C2 = GrB.eadd ('-', A, B)
+
+C1 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  7 nonzeros, 7 entries
+
+    (1,1)    -0.666139
+    (3,1)    -0.735859
+    (1,2)    -0.334348
+    (2,2)    -0.146938
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+
+C2 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  7 nonzeros, 7 entries
+
+    (1,1)    0.666139
+    (3,1)    0.735859
+    (1,2)    -0.334348
+    (2,2)    0.146938
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+

But these give the same result

C1 = A-B
+C2 = GrB.eadd ('+', A, GrB.apply ('-', B))
+err = norm (C1-C2,1)
+
+C1 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  7 nonzeros, 7 entries
+
+    (1,1)    -0.666139
+    (3,1)    -0.735859
+    (1,2)    -0.334348
+    (2,2)    -0.146938
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+
+C2 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  7 nonzeros, 7 entries
+
+    (1,1)    -0.666139
+    (3,1)    -0.735859
+    (1,2)    -0.334348
+    (2,2)    -0.146938
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+err =
+     0
+

Element-wise 'multiplication'

For C = A.*B, the result C is the set intersection of the pattern of A and B. The operator is applied to entries in both A and B. Entries in A but not B, or B but not A, do not appear in the result C.

C1 = A.*B
+C2 = GrB.emult ('*', A, B)
+C3 = double (A) .* double (B)
+
+C1 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  1 nonzero, 1 entry
+
+    (1,2)    0.518474
+
+
+C2 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  1 nonzero, 1 entry
+
+    (1,2)    0.518474
+
+C3 =
+   (1,2)       0.5185
+

Just as in GrB.eadd, any operator can be used in GrB.emult:

A
+B
+C2 = GrB.emult ('max', A, B)
+
+A =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,2)    0.572029
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+
+B =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)    0.666139
+    (3,1)    0.735859
+    (1,2)    0.906378
+    (2,2)    0.146938
+
+
+C2 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  1 nonzero, 1 entry
+
+    (1,2)    0.906378
+
+

Overloaded operators

The following operators all work as you would expect for any matrix. The matrices A and B can be GraphBLAS matrices, or MATLAB sparse or dense matrices, in any combination, or scalars where appropriate, The matrix M is logical (MATLAB or GraphBLAS):

  A+B   A-B  A*B   A.*B  A./B  A.\B  A.^b   A/b   C=A(I,J)  C(M)=A
+  -A    +A   ~A    A'    A.'   A&B   A|B    b\A   C(I,J)=A  C=A(M)
+  A~=B  A>B  A==B  A<=B  A>=B  A<B   [A,B]  [A;B] C(A)
+  A(1:end,1:end)

For A^b, b must be a non-negative integer.

C1 = [A B] ;
+C2 = [double(A) double(B)] ;
+assert (isequal (double (C1), C2))
+
C1 = A^2
+C2 = double (A)^2 ;
+err = norm (C1 - C2, 1)
+assert (err < 1e-12)
+
+C1 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  5 nonzeros, 5 entries
+
+    (2,2)    0.140946
+    (3,2)    0.0590838
+    (1,3)    0.142227
+    (2,3)    0.0259144
+    (3,3)    0.151809
+
+err =
+     0
+
C1 = A (1:2,2:end)
+A = double (A) ;
+C2 = A (1:2,2:end) ;
+assert (isequal (double (C1), C2))
+
+C1 =
+
+  2x2 GraphBLAS double matrix, sparse by col:
+  2 nonzeros, 2 entries
+
+    (1,1)    0.572029
+    (2,2)    0.248635
+
+

Overloaded functions

Many MATLAB built-in functions can be used with GraphBLAS matrices:

A few differences with the built-in functions:

S = sparse (G)        % makes a copy of a GrB matrix
+F = full (G)          % adds explicit zeros, so numel(F)==nnz(F)
+F = full (G,type,id)  % adds explicit identity values to a GrB matrix
+disp (G, level)       % display a GrB matrix G; level=2 is the default.
+

In the list below, the first set of Methods are overloaded built-in methods. They are used as-is on GraphBLAS matrices, such as C=abs(G). The Static methods are prefixed with "GrB.", as in C = GrB.apply ( ... ).

methods GrB
+
+Methods for class GrB:
+
+GrB             disp            islogical       real            
+abs             display         ismatrix        repmat          
+acos            dmperm          isnan           reshape         
+acosh           double          isnumeric       round           
+acot            eig             isreal          sec             
+acoth           end             isscalar        sech            
+acsc            eps             issparse        sign            
+acsch           eq              issymmetric     sin             
+all             erf             istril          single          
+amd             erfc            istriu          sinh            
+and             etree           isvector        size            
+angle           exp             kron            sparse          
+any             expm1           ldivide         spfun           
+asec            false           le              spones          
+asech           find            length          sprand          
+asin            fix             log             sprandn         
+asinh           flip            log10           sprandsym       
+assert          floor           log1p           sprintf         
+atan            fprintf         log2            sqrt            
+atan2           full            logical         subsasgn        
+atanh           gamma           lt              subsindex       
+bandwidth       gammaln         max             subsref         
+bitand          ge              min             sum             
+bitcmp          graph           minus           symamd          
+bitget          gt              mldivide        symrcm          
+bitor           horzcat         mpower          tan             
+bitset          hypot           mrdivide        tanh            
+bitshift        imag            mtimes          times           
+bitxor          int16           ne              transpose       
+ceil            int32           nnz             tril            
+colamd          int64           nonzeros        triu            
+complex         int8            norm            true            
+conj            isa             not             uint16          
+cos             isbanded        numel           uint32          
+cosh            isdiag          nzmax           uint64          
+cot             isempty         ones            uint8           
+coth            isequal         or              uminus          
+csc             isfinite        plus            uplus           
+csch            isfloat         pow2            vertcat         
+ctranspose      ishermitian     power           xor             
+diag            isinf           prod            zeros           
+digraph         isinteger       rdivide         
+
+Static methods:
+
+MATLAB_vs_GrB   empty           issigned        reduce          
+apply           emult           kronecker       select          
+apply2          entries         ktruss          selectopinfo    
+assign          expand          laplacian       semiringinfo    
+bfs             extract         mis             speye           
+binopinfo       extracttuples   monoidinfo      subassign       
+build           eye             mxm             threads         
+burble          finalize        nonz            trans           
+chunk           format          normdiff        tricount        
+clear           incidence       offdiag         type            
+compact         init            optype          unopinfo        
+descriptorinfo  isbycol         pagerank        vreduce         
+dnn             isbyrow         prune           
+eadd            isfull          random          
+
+

Zeros are handled differently

Explicit zeros cannot be automatically dropped from a GraphBLAS matrix, like they are in MATLAB sparse matrices. In a shortest-path problem, for example, an edge A(i,j) that is missing has an infinite weight, (the monoid identity of min(x,y) is +inf). A zero edge weight A(i,j)=0 is very different from an entry that is not present in A. However, if a GraphBLAS matrix is converted into a MATLAB sparse matrix, explicit zeros are dropped, which is the convention for a MATLAB sparse matrix. They can also be dropped from a GraphBLAS matrix using the GrB.select method.

G = GrB (magic (2)) ;
+G (1,1) = 0      % G(1,1) still appears as an explicit entry
+A = double (G)   % but it's dropped when converted to MATLAB sparse
+H = GrB.select ('nonzero', G)  % drops the explicit zeros from G
+fprintf ('nnz (G): %d  nnz (A): %g nnz (H): %g\n', ...
+    nnz (G), nnz (A), nnz (H)) ;
+fprintf ('num entries in G: %d\n', GrB.entries (G)) ;
+
+G =
+
+  2x2 GraphBLAS double matrix, sparse by col:
+  3 nonzeros, 4 entries
+
+    (1,1)    0
+    (2,1)    4
+    (1,2)    3
+    (2,2)    2
+
+A =
+   (2,1)        4
+   (1,2)        3
+   (2,2)        2
+
+H =
+
+  2x2 GraphBLAS double matrix, sparse by col:
+  3 nonzeros, 3 entries
+
+    (2,1)    4
+    (1,2)    3
+    (2,2)    2
+
+nnz (G): 3  nnz (A): 3 nnz (H): 3
+num entries in G: 4
+

Displaying contents of a GraphBLAS matrix

Unlike MATLAB, the default is to display just a few entries of a GrB matrix. Here are all 100 entries of a 10-by-10 matrix, using a non-default disp(G,3):

G = GrB (rand (10)) ;
+% display everything:
+disp (G,3)
+
+G =
+
+  10x10 GraphBLAS double matrix, sparse by col:
+  100 nonzeros, 100 entries
+
+    (1,1)    0.0342763
+    (2,1)    0.17802
+    (3,1)    0.887592
+    (4,1)    0.889828
+    (5,1)    0.769149
+    (6,1)    0.00497062
+    (7,1)    0.735693
+    (8,1)    0.488349
+    (9,1)    0.332817
+    (10,1)    0.0273313
+    (1,2)    0.467212
+    (2,2)    0.796714
+    (3,2)    0.849463
+    (4,2)    0.965361
+    (5,2)    0.902248
+    (6,2)    0.0363252
+    (7,2)    0.708068
+    (8,2)    0.322919
+    (9,2)    0.700716
+    (10,2)    0.472957
+    (1,3)    0.204363
+    (2,3)    0.00931977
+    (3,3)    0.565881
+    (4,3)    0.183435
+    (5,3)    0.00843818
+    (6,3)    0.284938
+    (7,3)    0.706156
+    (8,3)    0.909475
+    (9,3)    0.84868
+    (10,3)    0.564605
+    (1,4)    0.075183
+    (2,4)    0.535293
+    (3,4)    0.072324
+    (4,4)    0.515373
+    (5,4)    0.926149
+    (6,4)    0.949252
+    (7,4)    0.0478888
+    (8,4)    0.523767
+    (9,4)    0.167203
+    (10,4)    0.28341
+    (1,5)    0.122669
+    (2,5)    0.441267
+    (3,5)    0.157113
+    (4,5)    0.302479
+    (5,5)    0.758486
+    (6,5)    0.910563
+    (7,5)    0.0246916
+    (8,5)    0.232421
+    (9,5)    0.38018
+    (10,5)    0.677531
+    (1,6)    0.869074
+    (2,6)    0.471459
+    (3,6)    0.624929
+    (4,6)    0.987186
+    (5,6)    0.282885
+    (6,6)    0.843833
+    (7,6)    0.869597
+    (8,6)    0.308209
+    (9,6)    0.201332
+    (10,6)    0.706603
+    (1,7)    0.563222
+    (2,7)    0.575795
+    (3,7)    0.056376
+    (4,7)    0.73412
+    (5,7)    0.608022
+    (6,7)    0.0400164
+    (7,7)    0.540801
+    (8,7)    0.023064
+    (9,7)    0.165682
+    (10,7)    0.250393
+    (1,8)    0.23865
+    (2,8)    0.232033
+    (3,8)    0.303191
+    (4,8)    0.579934
+    (5,8)    0.267751
+    (6,8)    0.916376
+    (7,8)    0.833499
+    (8,8)    0.978692
+    (9,8)    0.734445
+    (10,8)    0.102896
+    (1,9)    0.353059
+    (2,9)    0.738955
+    (3,9)    0.57539
+    (4,9)    0.751433
+    (5,9)    0.93256
+    (6,9)    0.281622
+    (7,9)    0.51302
+    (8,9)    0.24406
+    (9,9)    0.950086
+    (10,9)    0.303638
+    (1,10)    0.563593
+    (2,10)    0.705101
+    (3,10)    0.0604146
+    (4,10)    0.672065
+    (5,10)    0.359793
+    (6,10)    0.62931
+    (7,10)    0.977758
+    (8,10)    0.394328
+    (9,10)    0.765651
+    (10,10)    0.457809
+
+
+

That was disp(G,3), so every entry was printed. It's a little long, so the default is not to print everything.

With the default display (level = 2):

G
+
+G =
+
+  10x10 GraphBLAS double matrix, sparse by col:
+  100 nonzeros, 100 entries
+
+    (1,1)    0.0342763
+    (2,1)    0.17802
+    (3,1)    0.887592
+    (4,1)    0.889828
+    (5,1)    0.769149
+    (6,1)    0.00497062
+    (7,1)    0.735693
+    (8,1)    0.488349
+    (9,1)    0.332817
+    (10,1)    0.0273313
+    (1,2)    0.467212
+    (2,2)    0.796714
+    (3,2)    0.849463
+    (4,2)    0.965361
+    (5,2)    0.902248
+    (6,2)    0.0363252
+    (7,2)    0.708068
+    (8,2)    0.322919
+    (9,2)    0.700716
+    (10,2)    0.472957
+    (1,3)    0.204363
+    (2,3)    0.00931977
+    (3,3)    0.565881
+    (4,3)    0.183435
+    (5,3)    0.00843818
+    (6,3)    0.284938
+    (7,3)    0.706156
+    (8,3)    0.909475
+    (9,3)    0.84868
+    (10,3)    0.564605
+    ...
+
+

That was disp(G,2) or just display(G), which is what is printed by a MATLAB statement that doesn't have a trailing semicolon. With level = 1, disp(G,1) gives just a terse summary:

disp (G,1)
+
+G =
+
+  10x10 GraphBLAS double matrix, sparse by col:
+  100 nonzeros, 100 entries
+
+
+

Storing a matrix by row or by column

MATLAB stores its sparse matrices by column, refered to as 'standard CSC' in SuiteSparse:GraphBLAS. In the CSC (compressed sparse column) format, each column of the matrix is stored as a list of entries, with their value and row index. In the CSR (compressed sparse row) format, each row is stored as a list of values and their column indices. GraphBLAS uses both CSC and CSR, and the two formats can be intermixed arbitrarily. In its C interface, the default format is CSR. However, for better compatibility with MATLAB, this MATLAB interface for SuiteSparse:GraphBLAS uses CSC by default instead.

rng ('default') ;
+GrB.clear ;                      % clear prior GraphBLAS settings
+fprintf ('the default format is: %s\n', GrB.format) ;
+C = sparse (rand (2))
+G = GrB (C)
+GrB.format (G)
+
the default format is: by col
+C =
+   (1,1)       0.8147
+   (2,1)       0.9058
+   (1,2)       0.1270
+   (2,2)       0.9134
+
+G =
+
+  2x2 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)    0.814724
+    (2,1)    0.905792
+    (1,2)    0.126987
+    (2,2)    0.913376
+
+ans =
+    'by col'
+

Many graph algorithms work better in CSR format, with matrices stored by row. For example, it is common to use A(i,j) for the edge (i,j), and many graph algorithms need to access the out-adjacencies of nodes, which is the row A(i,;) for node i. If the CSR format is desired, GrB.format ('by row') tells GraphBLAS to create all subsequent matrices in the CSR format. Converting from a MATLAB sparse matrix (in standard CSC format) takes a little more time (requiring a transpose), but subsequent graph algorithms can be faster.

G = GrB (C, 'by row')
+fprintf ('the format of G is:    %s\n', GrB.format (G)) ;
+H = GrB (C)
+fprintf ('the format of H is:    %s\n', GrB.format (H)) ;
+err = norm (H-G,1)
+
+G =
+
+  2x2 GraphBLAS double matrix, sparse by row:
+  4 nonzeros, 4 entries
+
+    (1,1)    0.814724
+    (1,2)    0.126987
+    (2,1)    0.905792
+    (2,2)    0.913376
+
+the format of G is:    by row
+
+H =
+
+  2x2 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)    0.814724
+    (2,1)    0.905792
+    (1,2)    0.126987
+    (2,2)    0.913376
+
+the format of H is:    by col
+err =
+     0
+

Hypersparse matrices

SuiteSparse:GraphBLAS can use two kinds of sparse matrix data structures: standard and hypersparse, for both CSC and CSR formats. In the standard CSC format used in MATLAB, an m-by-n matrix A takes O(n+nnz(A)) space. MATLAB can create huge column vectors, but not huge matrices (when n is huge).

clear
+[c, huge] = computer ;
+C = sparse (huge, 1)    % MATLAB can create a huge-by-1 sparse column
+try
+    C = sparse (huge, huge)     % but this fails
+catch me
+    error_expected = me
+end
+
C =
+   All zero sparse: 281474976710655x1
+error_expected = 
+  MException with properties:
+
+    identifier: 'MATLAB:array:SizeLimitExceeded'
+       message: 'Requested 281474976710655x281474976710655 (2097152.0GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See <a href="matlab: helpview([docroot '/matlab/helptargets.map'], 'matlab_env_workspace_prefs')">array size limit</a> or preference panel for more information.'
+         cause: {0x1 cell}
+         stack: [4x1 struct]
+

In a GraphBLAS hypersparse matrix, an m-by-n matrix A takes only O(nnz(A)) space. The difference can be huge if nnz (A) << n.

clear
+[c, huge] = computer ;
+G = GrB (huge, 1)            % no problem for GraphBLAS
+H = GrB (huge, huge)         % this works in GraphBLAS too
+
+G =
+
+  281474976710655x1 GraphBLAS double matrix, sparse by col:
+  no nonzeros, no entries
+
+
+H =
+
+  281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
+  no nonzeros, no entries
+
+

Operations on huge hypersparse matrices are very fast; no component of the time or space complexity is Omega(n).

I = randperm (huge, 2) ;
+J = randperm (huge, 2) ;
+H (I,J) = magic (2) ;        % add 4 nonzeros to random locations in H
+H (I,I) = 10 * [1 2 ; 3 4] ; % so H^2 is not all zero
+H = H^2 ;                    % square H
+H = (H' * 2) ;               % transpose H and double the entries
+K = pi * spones (H) ;
+H = H + K                    % add pi to each entry in H
+
+H =
+
+  281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
+  8 nonzeros, 8 entries
+
+    (27455183225557,27455183225557)    4403.14
+    (78390279669562,27455183225557)    383.142
+    (153933462881710,27455183225557)    343.142
+    (177993304104065,27455183225557)    3003.14
+    (27455183225557,177993304104065)    2003.14
+    (78390279669562,177993304104065)    183.142
+    (153933462881710,177993304104065)    143.142
+    (177993304104065,177993304104065)    1403.14
+
+

numel uses vpa if the matrix is really huge

e1 = numel (G)               % this is huge, but still a flint
+e2 = numel (H)               % this is huge^2, which needs vpa
+whos e1 e2
+
e1 =
+   2.8147e+14
+e2 =
+79228162514263774643590529025.0
+  Name      Size            Bytes  Class     Attributes
+
+  e1        1x1                 8  double              
+  e2        1x1                 8  sym                 
+
+

All of these matrices take very little memory space:

whos C G H K
+
  Name                    Size                         Bytes  Class    Attributes
+
+  G         281474976710655x1                            981  GrB                
+  H         281474976710655x281474976710655             1300  GrB                
+  K         281474976710655x281474976710655             1300  GrB                
+
+

The mask and accumulator

When not used in overloaded operators or built-in functions, many GraphBLAS methods of the form GrB.method ( ... ) can optionally use a mask and/or an accumulator operator. If the accumulator is '+' in GrB.mxm, for example, then C = C + A*B is computed. The mask acts much like logical indexing in MATLAB. With a logical mask matrix M, C<M>=A*B allows only part of C to be assigned. If M(i,j) is true, then C(i,j) can be modified. If false, then C(i,j) is not modified.

For example, to set all values in C that are greater than 0.5 to 3:

A = rand (3)
+C = GrB.assign (A, A > 0.5, 3) ;     % in GraphBLAS
+C1 = GrB (A) ; C1 (A > .5) = 3       % also in GraphBLAS
+C2 = A       ; C2 (A > .5) = 3       % in MATLAB
+err = norm (C - C1, 1)
+err = norm (C - C2, 1)
+
A =
+    0.9575    0.9706    0.8003
+    0.9649    0.9572    0.1419
+    0.1576    0.4854    0.4218
+
+C1 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  9 nonzeros, 9 entries
+
+    (1,1)    3
+    (2,1)    3
+    (3,1)    0.157613
+    (1,2)    3
+    (2,2)    3
+    (3,2)    0.485376
+    (1,3)    3
+    (2,3)    0.141886
+    (3,3)    0.421761
+
+C2 =
+    3.0000    3.0000    3.0000
+    3.0000    3.0000    0.1419
+    0.1576    0.4854    0.4218
+err =
+     0
+err =
+     0
+

The descriptor

Most GraphBLAS functions of the form GrB.method ( ... ) take an optional last argument, called the descriptor. It is a MATLAB struct that can modify the computations performed by the method. 'help GrB.descriptorinfo' gives all the details. The following is a short summary of the primary settings:

d.out = 'default' or 'replace', clears C after the accum op is used.

d.mask = 'default' or 'complement', to use M or ~M as the mask matrix; 'structural', or 'structural complement', to use the pattern of M or ~M.

d.in0 = 'default' or 'transpose', to transpose A for C=A*B, C=A+B, etc.

d.in1 = 'default' or 'transpose', to transpose B for C=A*B, C=A+B, etc.

d.kind = 'default', 'GrB', 'sparse', or 'full'; the output of GrB.method.

A = sparse (rand (2)) ;
+B = sparse (rand (2)) ;
+C1 = A'*B ;
+C2 = GrB.mxm ('+.*', A, B, struct ('in0', 'transpose')) ;
+err = norm (C1-C2,1)
+
err =
+     0
+

Integer arithmetic is different in GraphBLAS

MATLAB supports integer arithmetic on its full matrices, using int8, int16, int32, int64, uint8, uint16, uint32, or uint64 data types. None of these integer data types can be used to construct a MATLAB sparse matrix, which can only be double, double complex, or logical. Furthermore, C=A*B is not defined for integer types in MATLAB, except when A and/or B are scalars.

GraphBLAS supports all of those types for its sparse matrices. All operations are supported, including C=A*B when A or B are any integer type, in 1000s of semirings.

However, integer arithmetic differs in GraphBLAS and MATLAB. In MATLAB, integer values saturate if they exceed their maximum value. In GraphBLAS, integer operators act in a modular fashion. The latter is essential when computing C=A*B over a semiring. A saturating integer operator cannot be used as a monoid since it is not associative.

C = uint8 (magic (3)) ;
+G = GrB (C) ;
+C1 = C * 40
+C2 = G * uint8 (40)
+S = double (C1 < 255) ;
+assert (isequal (double (C1).*S, double (C2).*S))
+
C1 =
+  3x3 uint8 matrix
+   255    40   240
+   120   200   255
+   160   255    80
+
+C2 =
+
+  3x3 GraphBLAS uint8_t matrix, sparse by col:
+  9 nonzeros, 9 entries
+
+    (1,1)   64
+    (2,1)   120
+    (3,1)   160
+    (1,2)   40
+    (2,2)   200
+    (3,2)   104
+    (1,3)   240
+    (2,3)   24
+    (3,3)   80
+
+

An example graph algorithm: breadth-first search

The breadth-first search of a graph finds all nodes reachable from the source node, and their level, v. v=GrB.bfs(A,s) or v=bfs_matlab(A,s) compute the same thing, but GrB.bfs uses GraphBLAS matrices and operations, while bfs_matlab uses pure MATLAB operations. v is defined as v(s) = 1 for the source node, v(i) = 2 for nodes adjacent to the source, and so on.

clear
+rng ('default') ;
+n = 1e5 ;
+A = logical (sprandn (n, n, 1e-3)) ;
+
+tic
+v1 = GrB.bfs (A, 1) ;
+gb_time = toc ;
+
+tic
+v2 = bfs_matlab (A, 1) ;
+matlab_time = toc ;
+
+assert (isequal (double (v1'), v2))
+fprintf ('\nnodes reached: %d of %d\n', nnz (v2), n) ;
+fprintf ('GraphBLAS time: %g sec\n', gb_time) ;
+fprintf ('MATLAB time:    %g sec\n', matlab_time) ;
+fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
+    matlab_time / gb_time) ;
+
+nodes reached: 100000 of 100000
+GraphBLAS time: 0.0654 sec
+MATLAB time:    1.09345 sec
+Speedup of GraphBLAS over MATLAB: 16.7194
+

Example graph algorithm: Luby's method in GraphBLAS

The GrB.mis function is variant of Luby's randomized algorithm [Luby 1985]. It is a parallel method for finding an maximal independent set of nodes, where no two nodes are adjacent. See the GraphBLAS/@GrB/mis.m function for details. The graph must be symmetric with a zero-free diagonal, so A is symmetrized first and any diagonal entries are removed.

A = GrB (A) ;
+A = GrB.offdiag (A|A') ;
+
+tic
+s = GrB.mis (A) ;
+toc
+fprintf ('# nodes in the graph: %g\n', size (A,1)) ;
+fprintf ('# edges: : %g\n', GrB.entries (A) / 2) ;
+fprintf ('size of maximal independent set found: %g\n', ...
+    full (double (sum (s)))) ;
+
+% make sure it's independent
+p = find (s) ;
+S = A (p,p) ;
+assert (GrB.entries (S) == 0)
+
+% make sure it's maximal
+notp = find (s == 0) ;
+S = A (notp, p) ;
+deg = GrB.vreduce ('+.int64', S) ;
+assert (logical (all (deg > 0)))
+
Elapsed time is 0.257117 seconds.
+# nodes in the graph: 100000
+# edges: : 9.9899e+06
+size of maximal independent set found: 2811
+

Sparse deep neural network

The 2019 MIT GraphChallenge (see http://graphchallenge.org) is to solve a set of large sparse deep neural network problems. In this demo, the MATLAB reference solution is compared with a solution using GraphBLAS, for a randomly constructed neural network. See the GrB.dnn and dnn_matlab.m functions for details.

clear
+rng ('default') ;
+nlayers = 16 ;
+nneurons = 4096 ;
+nfeatures = 30000 ;
+fprintf ('# layers:   %d\n', nlayers) ;
+fprintf ('# neurons:  %d\n', nneurons) ;
+fprintf ('# features: %d\n', nfeatures) ;
+
+tic
+Y0 = sprand (nfeatures, nneurons, 0.1) ;
+for layer = 1:nlayers
+    W {layer} = sprand (nneurons, nneurons, 0.01) * 0.2 ;
+    bias {layer} = -0.2 * ones (1, nneurons) ;
+end
+t_setup = toc ;
+fprintf ('construct problem time: %g sec\n', t_setup) ;
+
+% convert the problem from MATLAB to GraphBLAS
+t = tic ;
+[W_gb, bias_gb, Y0_gb] = dnn_mat2gb (W, bias, Y0) ;
+t = toc (t) ;
+fprintf ('setup time: %g sec\n', t) ;
+
# layers:   16
+# neurons:  4096
+# features: 30000
+construct problem time: 7.72332 sec
+setup time: 0.091834 sec
+

Solving the sparse deep neural network problem with GraphbLAS

Please wait ...

tic
+Y1 = GrB.dnn (W_gb, bias_gb, Y0_gb) ;
+gb_time = toc ;
+fprintf ('total time in GraphBLAS: %g sec\n', gb_time) ;
+
total time in GraphBLAS: 2.94826 sec
+

Solving the sparse deep neural network problem with MATLAB

Please wait ...

tic
+Y2 = dnn_matlab (W, bias, Y0) ;
+matlab_time = toc ;
+fprintf ('total time in MATLAB:    %g sec\n', matlab_time) ;
+fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
+    matlab_time / gb_time) ;
+
+err = norm (Y1-Y2,1)
+
total time in MATLAB:    127.537 sec
+Speedup of GraphBLAS over MATLAB: 43.2585
+err =
+     0
+

For objects, GraphBLAS has better colon notation than MATLAB

The MATLAB notation C = A (start:inc:fini) is very handy, and it works great if A is a MATLAB matrix. But for objects like the GraphBLAS matrix, MATLAB starts by creating the explicit index vector I = start:inc:fini. That's fine if the matrix is modest in size, but GraphBLAS can construct huge matrices. The problem is that 1:n cannot be explicitly constructed when n is huge.

The C API for GraphBLAS can represent the colon notation start:inc:fini in an implicit manner, so it can do the indexing without actually forming the explicit list I = start:inc:fini. But there is no access to this method using the MATLAB notation start:inc:fini.

Thus, to compute C = A (start:inc:fini) for very huge matrices, you need to use use a cell array to represent the colon notation, as { start, inc, fini }, instead of start:inc:fini. See 'help GrB.extract', 'help GrB.assign' for the functional form. For the overloaded syntax C(I,J)=A and C=A(I,J), see 'help GrB/subsasgn' and 'help GrB/subsfref'. The cell array syntax isn't conventional, but it is far faster than the MATLAB colon notation for objects, and takes far less memory when I is huge.

n = 1e14 ;
+H = GrB (n, n) ;            % a huge empty matrix
+I = [1 1e9 1e12 1e14] ;
+M = magic (4)
+H (I,I) = M ;
+J = {1, 1e13} ;            % represents 1:1e13 colon notation
+C1 = H (J, J)              % computes C1 = H (1:e13,1:1e13)
+c = nonzeros (C1) ;
+m = nonzeros (M (1:3, 1:3)) ;
+assert (isequal (c, m)) ;
+
M =
+    16     2     3    13
+     5    11    10     8
+     9     7     6    12
+     4    14    15     1
+
+C1 =
+
+  10000000000000x10000000000000 GraphBLAS double matrix, hypersparse by col:
+  9 nonzeros, 9 entries
+
+    (1,1)    16
+    (1000000000,1)    5
+    (1000000000000,1)    9
+    (1,1000000000)    2
+    (1000000000,1000000000)    11
+    (1000000000000,1000000000)    7
+    (1,1000000000000)    3
+    (1000000000,1000000000000)    10
+    (1000000000000,1000000000000)    6
+
+
try
+    % try to compute the same thing with colon
+    % notation (1:1e13), but this fails:
+    C2 = H (1:1e13, 1:1e13)
+catch me
+    error_expected = me
+end
+
error_expected = 
+  MException with properties:
+
+    identifier: 'MATLAB:array:SizeLimitExceeded'
+       message: 'Requested 10000000000000x1 (74505.8GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See <a href="matlab: helpview([docroot '/matlab/helptargets.map'], 'matlab_env_workspace_prefs')">array size limit</a> or preference panel for more information.'
+         cause: {}
+         stack: [4x1 struct]
+

Iterative solvers work as-is

Many built-in functions work with GraphBLAS matrices unmodified.

A = sparse (rand (4)) ;
+b = sparse (rand (4,1)) ;
+x = gmres (A,b)
+norm (A*x-b)
+x = gmres (GrB(A), GrB(b))
+norm (A*x-b)
+
gmres converged at iteration 4 to a solution with relative residual 0.
+x =
+    0.9105
+    3.8949
+   -0.5695
+   -1.3867
+ans =
+   8.6711e-16
+gmres converged at iteration 4 to a solution with relative residual 0.
+x =
+    0.9105
+    3.8949
+   -0.5695
+   -1.3867
+ans =
+   7.2802e-16
+

... even in single precision

x = gmres (GrB(A,'single'), GrB(b,'single'))
+norm (A*x-b)
+
gmres converged at iteration 4 to a solution with relative residual 0.
+x =
+    0.9105
+    3.8949
+   -0.5695
+   -1.3867
+ans =
+   8.3369e-08
+

Both of the following uses of minres (A,b) fail to converge because A is not symmetric, as the method requires. Both failures are correctly reported, and both the MATLAB version and the GraphBLAS version return the same incorrect vector x.

x = minres (A, b)
+x = minres (GrB(A), GrB(b))
+
minres stopped at iteration 4 without converging to the desired tolerance 1e-06
+because the maximum number of iterations was reached.
+The iterate returned (number 4) has relative residual 0.21.
+x =
+    0.2489
+    0.2081
+    0.0700
+    0.3928
+minres stopped at iteration 4 without converging to the desired tolerance 1e-06
+because the maximum number of iterations was reached.
+The iterate returned (number 4) has relative residual 0.21.
+
+x =
+
+  4x1 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)    0.248942
+    (2,1)    0.208128
+    (3,1)    0.0699707
+    (4,1)    0.392812
+
+

With a proper symmetric matrix

A = A+A' ;
+x = minres (A, b)
+norm (A*x-b)
+x = minres (GrB(A), GrB(b))
+norm (A*x-b)
+
minres converged at iteration 4 to a solution with relative residual 1.3e-11.
+x =
+ -114.0616
+   -1.4211
+  134.8227
+    2.0694
+ans =
+   1.3650e-11
+minres converged at iteration 4 to a solution with relative residual 1.3e-11.
+
+x =
+
+  4x1 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)    -114.062
+    (2,1)    -1.4211
+    (3,1)    134.823
+    (4,1)    2.0694
+
+ans =
+   1.3650e-11
+

Extreme performance differences between GraphBLAS and MATLAB.

The GraphBLAS operations used so far are perhaps 2x to 50x faster than the corresponding MATLAB operations, depending on how many cores your computer has. To run a demo illustrating a 500x or more speedup versus MATLAB, run this demo:

  gbdemo2

It will illustrate an assignment C(I,J)=A that can take under a second in GraphBLAS but several minutes in MATLAB. To make the comparsion even more dramatic, try:

  gbdemo2 (20000)

assuming you have enough memory.

Sparse logical indexing is much, much faster in GraphBLAS

The mask in GraphBLAS acts much like logical indexing in MATLAB, but it is not quite the same. MATLAB logical indexing takes the form:

     C (M) = A (M)

which computes the same thing as the GraphBLAS statement:

     C = GrB.assign (C, M, A)

The GrB.assign statement computes C(M)=A(M), and it is vastly faster than C(M)=A(M), even if the time to convert the GrB matrix back to a MATLAB sparse matrix is included.

GraphBLAS can also compute C (M) = A (M) using overloaded operators for subsref and subsasgn, but C = GrB.assign (C, M, A) is a bit faster.

Here are both methods in GraphBLAS (both are very fast). Setting up:

clear
+n = 4000 ;
+tic
+C = sprand (n, n, 0.1) ;
+A = 100 * sprand (n, n, 0.1) ;
+M = (C > 0.5) ;
+t_setup = toc ;
+fprintf ('nnz(C): %g, nnz(M): %g, nnz(A): %g\n', ...
+    nnz(C), nnz(M), nnz(A)) ;
+fprintf ('\nsetup time:     %g sec\n', t_setup) ;
+
nnz(C): 1.5226e+06, nnz(M): 761163, nnz(A): 1.52245e+06
+
+setup time:     1.29904 sec
+

First method in GraphBLAS, with GrB.assign

Including the time to convert C1 from a GraphBLAS matrix to a MATLAB sparse matrix:

tic
+C1 = GrB.assign (C, M, A) ;
+C1 = double (C1) ;
+gb_time = toc ;
+fprintf ('\nGraphBLAS time: %g sec for GrB.assign\n', gb_time) ;
+
+GraphBLAS time: 0.014748 sec for GrB.assign
+

Second method in GraphBLAS, with C(M)=A(M)

now using overloaded operators, also include the time to convert back to a MATLAB sparse matrix, for good measure:

A2 = GrB (A) ;
+C2 = GrB (C) ;
+tic
+C2 (M) = A2 (M) ;
+C2 = double (C2) ;
+gb_time2 = toc ;
+fprintf ('\nGraphBLAS time: %g sec for C(M)=A(M)\n', gb_time2) ;
+
+GraphBLAS time: 0.028518 sec for C(M)=A(M)
+

Now with MATLAB matrices, with C(M)=A(M)

Please wait, this will take about 10 minutes or so ...

tic
+C (M) = A (M) ;
+matlab_time = toc ;
+
+fprintf ('\nGraphBLAS time: %g sec (GrB.assign)\n', gb_time) ;
+fprintf ('\nGraphBLAS time: %g sec (overloading)\n', gb_time2) ;
+fprintf ('MATLAB time:    %g sec\n', matlab_time) ;
+fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
+    matlab_time / gb_time2) ;
+
+% GraphBLAS computes the exact same result with both methods:
+assert (isequal (C1, C))
+assert (isequal (C2, C))
+C1 - C
+C2 - C
+
+GraphBLAS time: 0.014748 sec (GrB.assign)
+
+GraphBLAS time: 0.028518 sec (overloading)
+MATLAB time:    1167.24 sec
+Speedup of GraphBLAS over MATLAB: 40930
+ans =
+   All zero sparse: 4000x4000
+ans =
+   All zero sparse: 4000x4000
+

Limitations and their future solutions

The MATLAB interface for SuiteSparse:GraphBLAS is a work-in-progress. It has some limitations, most of which will be resolved over time.

(1) Nonblocking mode:

GraphBLAS has a 'non-blocking' mode, in which operations can be left pending and completed later. SuiteSparse:GraphBLAS uses the non-blocking mode to speed up a sequence of assignment operations, such as C(I,J)=A. However, in its MATLAB interface, this would require a MATLAB mexFunction to modify its inputs. That breaks the MATLAB API standard, so it cannot be safely done. As a result, using GraphBLAS via its MATLAB interface can be slower than when using its C API.

(2) Integer element-wise operations:

Integer operations in MATLAB saturate, so that uint8(255)+1 is 255. To allow for integer monoids, GraphBLAS uses modular arithmetic instead. This is the only way that C=A*B can be defined for integer semirings. However, saturating integer operators could be added in the future, so that element- wise integer operations on GraphBLAS sparse integer matrices could work just the same as their MATLAB counterparts.

So in the future, you could perhaps write this, for both sparse and dense integer matrices A and B:

     C = GrB.eadd ('+saturate.int8', A, B)

to compute the same thing as C=A+B in MATLAB for its full int8 matrices. Note that MATLAB can do this only for dense integer matrices, since it doesn't support sparse integer matrices.

(3) Faster methods:

Most methods in this MATLAB interface are based on efficient parallel C functions in GraphBLAS itself, and are typically as fast or faster than the equivalent built-in operators and functions in MATLAB.

There are few notable exceptions; these will be addressed in the future. Dense matrices and vectors held as GraphBLAS objects are slower than their MATLAB counterparts. horzcat and vertcat, for [A B] and [A;B] when either A or B are GraphBLAS matrices, are also slow, as illustrated below in the next example.

Other methods that will be faster in the future include bandwidth, istriu, istril, isdiag, reshape, issymmetric, and ishermitian.

Here is an example that illustrates the performance of C = [A B]

clear
+A = sparse (rand (2000)) ;
+B = sparse (rand (2000)) ;
+tic
+C1 = [A B] ;
+matlab_time = toc ;
+
+A = GrB (A) ;
+B = GrB (B) ;
+tic
+C2 = [A B] ;
+gb_time = toc ;
+
+err = norm (C1-C2,1)
+fprintf ('\nMATLAB: %g sec, GraphBLAS: %g sec\n', ...
+    matlab_time, gb_time) ;
+if (gb_time > matlab_time)
+    fprintf ('GraphBLAS is slower by a factor of %g\n', ...
+        gb_time / matlab_time) ;
+end
+
err =
+     0
+
+MATLAB: 0.069112 sec, GraphBLAS: 0.183674 sec
+GraphBLAS is slower by a factor of 2.65763
+

(4) Linear indexing:

If A is an m-by-n 2D MATLAB matrix, with n > 1, A(:) is a column vector of length m*n. The index operation A(i) accesses the ith entry in the vector A(:). This is called linear indexing in MATLAB. It is not yet available for GraphBLAS matrices in this MATLAB interface to GraphBLAS, but will be added in the future.

(5) Implicit singleton dimension expansion

In MATLAB C=A+B where A is m-by-n and B is a 1-by-n row vector implicitly expands B to a matrix, computing C(i,j)=A(i,j)+B(j). This implicit expansion is not yet suported in GraphBLAS with C=A+B. However, it can be done with C = GrB.mxm ('+.+', A, diag(GrB(B))). That's a nice example of the power of semirings, but it's not immediately obvious, and not as clear a syntax as C=A+B. The GraphBLAS/@GrB/dnn.m function uses this 'plus.plus' semiring to apply the bias to each neuron.

A = magic (3)
+B = 1000:1000:3000
+C1 = A + B
+C2 = GrB.mxm ('+.+', A, diag (GrB (B)))
+err = norm (C1-C2,1)
+
A =
+     8     1     6
+     3     5     7
+     4     9     2
+B =
+        1000        2000        3000
+C1 =
+        1008        2001        3006
+        1003        2005        3007
+        1004        2009        3002
+
+C2 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  9 nonzeros, 9 entries
+
+    (1,1)    1008
+    (2,1)    1003
+    (3,1)    1004
+    (1,2)    2001
+    (2,2)    2005
+    (3,2)    2009
+    (1,3)    3006
+    (2,3)    3007
+    (3,3)    3002
+
+err =
+     0
+

(6) Performance issues

The GrB matrix is a MATLAB object, and there are some cases where performance issues can arise. Extracting the contents of a MATLAB object (G.field) takes much more time than for a MATLAB struct with the same syntax, and building an object has similar issues. The difference is small, and it does not affect large problems. But if you have many calls to GrB operations with a small amount of work, then the time can be dominated by the MATLAB object-oriented overhead.

A = rand (3,4) ;
+G = GrB (A) ;
+tic
+for k = 1:100000
+    [m, n] = size (A) ;
+end
+toc
+tic
+for k = 1:100000
+    [m, n] = size (G) ;
+end
+toc
+
Elapsed time is 0.108922 seconds.
+Elapsed time is 0.976359 seconds.
+

GraphBLAS operations

In addition to the overloaded operators (such as C=A*B) and overloaded functions (such as L=tril(A)), GraphBLAS also has methods of the form GrB.method. Most of them take an optional input matrix Cin, which is the initial value of the matrix C for the expression below, an optional mask matrix M, and an optional accumulator operator.

    C<#M,replace> = accum (C, T)

In the above expression, #M is either empty (no mask), M (with a mask matrix) or ~M (with a complemented mask matrix), as determined by the descriptor. 'replace' can be used to clear C after it is used in accum(C,T) but before it is assigned with C<...> = Z, where Z=accum(C,T). The matrix T is the result of some operation, such as T=A*B for GrB.mxm, or T=op(A,B) for GrB.eadd.

For a complete list of GraphBLAS overloaded operators and methods, type:

help GrB
+

Thanks for watching!

Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis See also doc sparse and https://twitter.com/DocSparse

\ No newline at end of file diff --git a/GraphBLAS/demo/html/DGX_Station/graphblas_demo2.html b/GraphBLAS/demo/html/DGX_Station/graphblas_demo2.html new file mode 100644 index 0000000000..489b858651 --- /dev/null +++ b/GraphBLAS/demo/html/DGX_Station/graphblas_demo2.html @@ -0,0 +1,196 @@ + + + + + graphblas_demo2
% Run the GraphBLAS demo2
+
+% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved.
+% http://suitesparse.com   See GraphBLAS/Doc/License.txt for license.
+
+gbdemo2
+
 GBDEMO2 Extreme performance differences: GraphBLAS vs MATLAB.
+ 
+  Usage:
+ 
+        gbdemo2             % uses a default bnz = 6000
+        gbdemo2 (20000)     % uses bnz = 20000
+ 
+  The GraphBLAS operations used in gbdemo are perhaps 3x to 50x
+  faster than the corresponding MATLAB operations, depending on how
+  many cores your computer has.  Here's an example where GraphBLAS is
+  asymptotically far faster than MATLAB R2019a: a simple assignment
+  for a large matrix C:
+ 
+        C(I,J) = A
+ 
+  The matrix C is constructed via C = kron (B,B) where nnz (B) is
+  roughly the bnz provided on input (with a default of bnz = 6000),
+  so that C will have about bnz^2 entries, or 36 million by default.
+  I and J are chosen randomly, and A is 5000-by-5000.
+ 
+  When the problem becomes large, MATLAB will take a very long time.
+  If you have enough memory, and want to see higher speedups in
+  GraphBLAS, increase bnz (and be prepared to wait even longer).
+  With the default bnz = 6000, this test takes about 4GB of RAM.
+ 
+  On my Dell XPS 4-core laptop (Intel(R) Core(TM) i7-8565U, 16GB
+  RAM), using MATLAB R2019a, when C becomes 9 million by 9 million,
+  the computation C(I,J)=A for MATLAB matrices C, I, J, and A takes
+  several minutes, whereas GraphBLAS takes less than a second, or
+  about 500x faster than MATLAB.  On a desktop with an Intel(R)
+  Xeon(R) CPU E5-2698 v4 @ 2.20GHz with 20 hardware cores, the
+  speedup over MATLAB is even more dramatic (up to 2,660x has been
+  observed).
+ 
+  See also GrB.assign, subsasgn.
+
+
+# of threads used in GraphBLAS: 20
+
+
+C(I,J)=A where C is 1 million -by- 1 million
+with 35.7126 million entries:
+
+    A is 5000-by-5000 with 49954 entries
+    setup time:     0.329855 sec
+    GraphBLAS time: 0.173019 sec
+    Starting MATLAB ... please wait ... 
+    MATLAB time:    0.474924 sec
+    Speedup of GraphBLAS over MATLAB: 2.74492
+    check time:     0.215864 sec
+    all tests passed
+
+C(I,J)=A where C is 4 million -by- 4 million
+with 35.8202 million entries:
+
+    A is 5000-by-5000 with 49954 entries
+    setup time:     0.417582 sec
+    GraphBLAS time: 0.203017 sec
+    Starting MATLAB ... please wait ... 
+    MATLAB time:    0.453103 sec
+    Speedup of GraphBLAS over MATLAB: 2.23185
+    check time:     0.22641 sec
+    all tests passed
+
+C(I,J)=A where C is 9 million -by- 9 million
+with 35.928 million entries:
+
+    A is 5000-by-5000 with 49954 entries
+    setup time:     0.485024 sec
+    GraphBLAS time: 0.249401 sec
+    Starting MATLAB ... please wait ... 
+    MATLAB time:    228.188 sec
+    Speedup of GraphBLAS over MATLAB: 914.945
+    check time:     0.249945 sec
+    all tests passed
+
+C(I,J)=A where C is 16 million -by- 16 million
+with 35.916 million entries:
+
+    A is 5000-by-5000 with 49954 entries
+    setup time:     0.552762 sec
+    GraphBLAS time: 0.292017 sec
+    Starting MATLAB ... please wait ... 
+    MATLAB time:    246.474 sec
+    Speedup of GraphBLAS over MATLAB: 844.041
+    check time:     0.27686 sec
+    all tests passed
+
+C(I,J)=A where C is 25 million -by- 25 million
+with 35.964 million entries:
+
+    A is 5000-by-5000 with 49954 entries
+    setup time:     0.630048 sec
+    GraphBLAS time: 0.25246 sec
+    Starting MATLAB ... please wait ... 
+    MATLAB time:    269.415 sec
+    Speedup of GraphBLAS over MATLAB: 1067.16
+    check time:     0.311659 sec
+    all tests passed
+
+C(I,J)=A where C is 36 million -by- 36 million
+with 35.976 million entries:
+
+    A is 5000-by-5000 with 49954 entries
+    setup time:     0.712427 sec
+    GraphBLAS time: 0.401151 sec
+    Starting MATLAB ... please wait ... 
+    MATLAB time:    296.906 sec
+    Speedup of GraphBLAS over MATLAB: 740.134
+    check time:     0.35269 sec
+    all tests passed
+
\ No newline at end of file diff --git a/GraphBLAS/demo/html/DGX_Station/v310/graphblas_demo.pdf b/GraphBLAS/demo/html/DGX_Station/v310/graphblas_demo.pdf deleted file mode 100644 index 94cea6aa9e..0000000000 Binary files a/GraphBLAS/demo/html/DGX_Station/v310/graphblas_demo.pdf and /dev/null differ diff --git a/GraphBLAS/demo/html/DGX_Station/v310/graphblas_demo2.pdf b/GraphBLAS/demo/html/DGX_Station/v310/graphblas_demo2.pdf deleted file mode 100644 index cf389b283d..0000000000 Binary files a/GraphBLAS/demo/html/DGX_Station/v310/graphblas_demo2.pdf and /dev/null differ diff --git a/GraphBLAS/demo/html/DGX_Station/v312/graphblas_demo.html b/GraphBLAS/demo/html/DGX_Station/v312/graphblas_demo.html deleted file mode 100644 index df34dfe834..0000000000 --- a/GraphBLAS/demo/html/DGX_Station/v312/graphblas_demo.html +++ /dev/null @@ -1,2685 +0,0 @@ - - - - - GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS is a library for creating graph algorithms based on sparse linear algebraic operations over semirings. Visit http://graphblas.org for more details and resources. See also the SuiteSparse:GraphBLAS User Guide in this package.

SuiteSparse:GraphBLAS, (c) 2017-2019, Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis

Contents

GraphBLAS: faster and more general sparse matrices for MATLAB

GraphBLAS is not only useful for creating graph algorithms; it also supports a wide range of sparse matrix data types and operations. MATLAB can compute C=A*B with just two semirings: 'plus.times.double' and 'plus.times.complex' for complex matrices. GraphBLAS has 1,040 unique built-in semirings, such as 'max.plus' (https://en.wikipedia.org/wiki/Tropical_semiring). These semirings can be used to construct a wide variety of graph algorithms, based on operations on sparse adjacency matrices.

GraphBLAS supports sparse double and single precision matrices, logical, and sparse integer matrices: int8, int16, int32, int64, uint8, uint16, uint32, and uint64. Complex matrices will be added in the future.

clear all
-format compact
-rng ('default') ;
-X = 100 * rand (2) ;
-G = GrB (X)              % GraphBLAS copy of a matrix X, same type
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    81.4724
-    (2,1)    90.5792
-    (1,2)    12.6987
-    (2,2)    91.3376
-
-

Sparse integer matrices

Here's an int8 version of the same matrix:

S = int8 (G)            % convert G to a full MATLAB int8 matrix
-G = GrB (X, 'int8')      % a GraphBLAS sparse int8 matrix
-
S =
-  2x2 int8 matrix
-   81   12
-   90   91
-
-G =
-
-  2x2 GraphBLAS int8_t matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)   81
-    (2,1)   90
-    (1,2)   12
-    (2,2)   91
-
-

Sparse single-precision matrices

Matrix operations in GraphBLAS are typically as fast, or faster than MATLAB. Here's an unfair comparison: computing X^2 with MATLAB in double precision and with GraphBLAS in single precision. You would naturally expect GraphBLAS to be faster.

Please wait ...

n = 1e5 ;
-X = spdiags (rand (n, 201), -100:100, n, n) ;
-G = GrB (X, 'single') ;
-tic
-G2 = G^2 ;
-gb_time = toc ;
-tic
-X2 = X^2 ;
-matlab_time = toc ;
-fprintf ('\nGraphBLAS time: %g sec (in single)\n', gb_time) ;
-fprintf ('MATLAB time:    %g sec (in double)\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
-GraphBLAS time: 0.674411 sec (in single)
-MATLAB time:    9.63083 sec (in double)
-Speedup of GraphBLAS over MATLAB: 14.2804
-

Mixing MATLAB and GraphBLAS matrices

The error in the last computation is about eps('single') since GraphBLAS did its computation in single precision, while MATLAB used double precision. MATLAB and GraphBLAS matrices can be easily combined, as in X2-G2. The sparse single precision matrices take less memory space.

err = norm (X2 - G2, 1) / norm (X2,1)
-eps ('single')
-whos G G2 X X2
-
err =
-   1.5049e-07
-ans =
-  single
-  1.1921e-07
-  Name           Size                    Bytes  Class     Attributes
-
-  G         100000x100000            241879772  GrB                 
-  G2        100000x100000            481518572  GrB                 
-  X         100000x100000            322238408  double    sparse    
-  X2        100000x100000            641756808  double    sparse    
-
-

Faster matrix operations

But even with standard double precision sparse matrices, GraphBLAS is typically faster than the built-in MATLAB methods. Here's a fair comparison:

G = GrB (X) ;
-tic
-G2 = G^2 ;
-gb_time = toc ;
-err = norm (X2 - G2, 1) / norm (X2,1)
-fprintf ('\nGraphBLAS time: %g sec (in double)\n', gb_time) ;
-fprintf ('MATLAB time:    %g sec (in double)\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
err =
-     0
-
-GraphBLAS time: 0.613755 sec (in double)
-MATLAB time:    9.63083 sec (in double)
-Speedup of GraphBLAS over MATLAB: 15.6917
-

A wide range of semirings

MATLAB can only compute C=A*B using the standard '+.*.double' and '+.*.complex' semirings. A semiring is defined in terms of a string, 'add.mult.type', where 'add' is a monoid that takes the place of the additive operator, 'mult' is the multiplicative operator, and 'type' is the data type for the two inputs to the mult operator (the type defaults to the type of A for C=A*B).

In the standard semiring, C=A*B is defined as:

C(i,j) = sum (A(i,:).' .* B(:,j))
-

using 'plus' as the monoid and 'times' as the multiplicative operator. But in a more general semiring, 'sum' can be any monoid, which is an associative and commutative operator that has an identity value. For example, in the 'max.plus' tropical algebra, C(i,j) for C=A*B is defined as:

C(i,j) = max (A(i,:).' + B(:,j))
-

This can be computed in GraphBLAS with:

C = GrB.mxm ('max.+', A, B)
-
n = 3 ;
-A = rand (n) ;
-B = rand (n) ;
-C = zeros (n) ;
-for i = 1:n
-    for j = 1:n
-        C(i,j) = max (A (i,:).' + B (:,j)) ;
-    end
-end
-C2 = GrB.mxm ('max.+', A, B) ;
-fprintf ('\nerr = norm (C-C2,1) = %g\n', norm (C-C2,1)) ;
-
-err = norm (C-C2,1) = 0
-

The max.plus tropical semiring

Here are details of the "max.plus" tropical semiring. The identity value is -inf since max(x,-inf) = max (-inf,x) = -inf for any x.

GrB.semiringinfo ('max.+.double') ;
-
-    GraphBLAS Semiring: max.+.double (built-in)
-    GraphBLAS Monoid: semiring->add (built-in)
-    GraphBLAS BinaryOp: monoid->op (built-in) z=max(x,y)
-    GraphBLAS type: ztype double size: 8
-    GraphBLAS type: xtype double size: 8
-    GraphBLAS type: ytype double size: 8
-    identity: [    -inf ] terminal: [    inf ]
-
-    GraphBLAS BinaryOp: semiring->multiply (built-in) z=plus(x,y)
-    GraphBLAS type: ztype double size: 8
-    GraphBLAS type: xtype double size: 8
-    GraphBLAS type: ytype double size: 8
-

A boolean semiring

MATLAB cannot multiply two logical matrices. MATLAB R2019a converts them to double and uses the conventional +.*.double semiring instead. In GraphBLAS, this is the common Boolean 'or.and.logical' semiring, which is widely used in linear algebraic graph algorithms.

GrB.semiringinfo ('|.&.logical') ;
-
-    GraphBLAS Semiring: |.&.logical (built-in)
-    GraphBLAS Monoid: semiring->add (built-in)
-    GraphBLAS BinaryOp: monoid->op (built-in) z=or(x,y)
-    GraphBLAS type: ztype bool size: 1
-    GraphBLAS type: xtype bool size: 1
-    GraphBLAS type: ytype bool size: 1
-    identity: [   0 ] terminal: [   1 ]
-
-    GraphBLAS BinaryOp: semiring->multiply (built-in) z=and(x,y)
-    GraphBLAS type: ztype bool size: 1
-    GraphBLAS type: xtype bool size: 1
-    GraphBLAS type: ytype bool size: 1
-
clear
-A = sparse (rand (3) > 0.5)
-B = sparse (rand (3) > 0.2)
-
A =
-  3x3 sparse logical array
-   (2,1)      1
-   (2,2)      1
-   (3,2)      1
-   (1,3)      1
-B =
-  3x3 sparse logical array
-   (1,1)      1
-   (2,1)      1
-   (3,1)      1
-   (1,2)      1
-   (2,2)      1
-   (3,2)      1
-   (1,3)      1
-   (2,3)      1
-   (3,3)      1
-
try
-    % MATLAB R2019a does this by casting A and B to double
-    C1 = A*B
-catch
-    % MATLAB R2018a throws an error
-    fprintf ('MATLAB R2019a required for C=A*B with logical\n') ;
-    fprintf ('matrices.  Explicitly converting to double:\n') ;
-    C1 = double (A) * double (B)
-end
-C2 = GrB (A) * GrB (B)
-
MATLAB R2019a required for C=A*B with logical
-matrices.  Explicitly converting to double:
-C1 =
-   (1,1)        1
-   (2,1)        2
-   (3,1)        1
-   (1,2)        1
-   (2,2)        2
-   (3,2)        1
-   (1,3)        1
-   (2,3)        2
-   (3,3)        1
-
-C2 =
-
-  3x3 GraphBLAS bool matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)   1
-    (2,1)   1
-    (3,1)   1
-    (1,2)   1
-    (2,2)   1
-    (3,2)   1
-    (1,3)   1
-    (2,3)   1
-    (3,3)   1
-
-

Note that C1 is a MATLAB sparse double matrix, and contains non-binary values. C2 is a GraphBLAS logical matrix.

whos
-GrB.type (C2)
-
  Name      Size            Bytes  Class      Attributes
-
-  A         3x3                68  logical    sparse    
-  B         3x3               113  logical    sparse    
-  C1        3x3               176  double     sparse    
-  C2        3x3              1079  GrB                  
-
-ans =
-    'logical'
-

GraphBLAS operators, monoids, and semirings

The C interface for SuiteSparse:GraphBLAS allows for arbitrary types and operators to be constructed. However, the MATLAB interface to SuiteSparse:GraphBLAS is restricted to pre-defined types and operators: a mere 11 types, 66 unary operators, 275 binary operators, 44 monoids, 16 select operators, and 1,865 semirings (1,040 of which are unique, since some binary operators are equivalent: 'min.logical' and '&.logical' are the same thing, for example). The complex type and its binary operators, monoids, and semirings will be added in the near future.

That gives you a lot of tools to create all kinds of interesting graph algorithms. For example:

GrB.bfs    % breadth-first search
-GrB.dnn    % sparse deep neural network (http://graphchallenge.org)
-GrB.mis    % maximal independent set
-

See 'help GrB.binopinfo' for a list of the binary operators, and 'help GrB.monoidinfo' for the ones that can be used as the additive monoid in a semiring.

help GrB.binopinfo
-
 GRB.BINOPINFO list the details of a GraphBLAS binary operator.
- 
-  Usage
- 
-    GrB.binopinfo
-    GrB.binopinfo (op)
-    GrB.binopinfo (op, type)
- 
-  For GrB.binopinfo(op), the op must be a string of the form
-  'op.type', where 'op' is listed below.  The second usage allows the
-  type to be omitted from the first argument, as just 'op'.  This is
-  valid for all GraphBLAS operations, since the type defaults to the
-  type of the input matrices.  However, GrB.binopinfo does not have a
-  default type and thus one must be provided, either in the op as
-  GrB.binopinfo ('+.double'), or in the second argument, GrB.binopinfo
-  ('+', 'double').
- 
-  The MATLAB interface to GraphBLAS provides for 25 different binary
-  operators, each of which may be used with any of the 11 types, for
-  a total of 25*11 = 275 valid binary operators.  Binary operators
-  are defined by a string of the form 'op.type', or just 'op'.  In
-  the latter case, the type defaults to the type of the matrix inputs
-  to the GraphBLAS operation.
- 
-  The 6 comparator operators come in two flavors.  For the is*
-  operators, the result has the same type as the inputs, x and y,
-  with 1 for true and 0 for false.  For example isgt.double (pi, 3.0)
-  is the double value 1.0.  For the second set of 6 operators (eq,
-  ne, gt, lt, ge, le), the result is always logical (true or false).
-  In a semiring, the type of the add monoid must exactly match the
-  type of the output of the multiply operator, and thus
-  'plus.iseq.double' is valid (counting how many terms are equal).
-  The 'plus.eq.double' semiring is valid, but not the same semiring
-  since the 'plus' of 'plus.eq.double' has a logical type and is thus
-  equivalent to 'or.eq.double'.   The 'or.eq' is true if any terms
-  are equal and false otherwise (it does not count the number of
-  terms that are equal).
- 
-  The following binary operators are available.  Many have equivalent
-  synonyms, so that '1st' and 'first' both define the first(x,y) = x
-  operator.
- 
-    operator name(s) f(x,y)         |   operator names(s) f(x,y)
-    ---------------- ------         |   ----------------- ------
-    1st first        x              |   iseq             x == y
-    2nd second       y              |   isne             x ~= y
-    min              min(x,y)       |   isgt             x > y
-    max              max(x,y)       |   islt             x < y
-    +   plus         x+y            |   isge             x >= y
-    -   minus        x-y            |   isle             x <= y
-    rminus           y-x            |   ==  eq           x == y
-    *   times        x*y            |   ~=  ne           x ~= y
-    /   div          x/y            |   >   gt           x > y
-    \   rdiv         y/x            |   <   lt           x < y
-    |   || or  lor   x | y          |   >=  ge           x >= y
-    &   && and land  x & y          |   <=  le           x <= y
-    xor lxor         xor(x,y)       |
- 
-  The three logical operators, lor, land, and lxor, also come in 11
-  types.  z = lor.double (x,y) tests the condition (x~=0) || (y~=0),
-  and returns the double value 1.0 if true, or 0.0 if false.
- 
-  Example:
- 
-    % valid binary operators
-    GrB.binopinfo ('+.double') ;
-    GrB.binopinfo ('1st.int32') ;
- 
-    % invalid binary operator (an error; this is a unary op):
-    GrB.binopinfo ('abs.double') ;
- 
-  See also GrB.descriptorinfo, GrB.monoidinfo, GrB.selectopinfo,
-  GrB.semiringinfo, GrB.unopinfo.
-
-
help GrB.monoidinfo
-
 GRB.MONOIDINFO list the details of a GraphBLAS monoid.
- 
-  Usage
- 
-    GrB.monoidinfo
-    GrB.monoidinfo (monoid)
-    GrB.monoidinfo (monoid, type)
- 
-  For GrB.monoidinfo(op), the op must be a string of the form
-  'op.type', where 'op' is listed below.  The second usage allows the
-  type to be omitted from the first argument, as just 'op'.  This is
-  valid for all GraphBLAS operations, since the type defaults to the
-  type of the input matrices.  However, GrB.monoidinfo does not have a
-  default type and thus one must be provided, either in the op as
-  GrB.monoidinfo ('+.double'), or in the second argument,
-  GrB.monoidinfo ('+', 'double').
- 
-  The MATLAB interface to GraphBLAS provides for 44 different
-  monoids.  The valid monoids are: '+', '*', 'max', and 'min' for all
-  but the 'logical' type, and '|', '&', 'xor', and 'eq' for the
-  'logical' type.
- 
-  Example:
- 
-    % valid monoids
-    GrB.monoidinfo ('+.double') ;
-    GrB.monoidinfo ('*.int32') ;
- 
-    % invalid monoids
-    GrB.monoidinfo ('1st.int32') ;
-    GrB.monoidinfo ('abs.double') ;
- 
-  See also GrB.binopinfo, GrB.descriptorinfo, % GrB.selectopinfo,
-  GrB.semiringinfo, GrB.unopinfo.
-
-

Element-wise operations

Binary operators can be used in element-wise matrix operations, like C=A+B and C=A.*B. For the matrix addition C=A+B, the pattern of C is the set union of A and B, and the '+' operator is applied for entries in the intersection. Entries in A but not B, or in B but not A, are assigned to C without using the operator. The '+' operator is used for C=A+B but any operator can be used with GrB.eadd.

A = GrB (sprand (3, 3, 0.5)) ;
-B = GrB (sprand (3, 3, 0.5)) ;
-C1 = A + B
-C2 = GrB.eadd ('+', A, B)
-err = norm (C1-C2,1)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    1.47841
-    (2,2)    0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    1.47841
-    (2,2)    0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-err =
-     0
-

Subtracting two matrices

A-B and GrB.eadd ('-', A, B) are not the same thing, since the '-' operator is not applied to an entry that is in B but not A.

C1 = A-B
-C2 = GrB.eadd ('-', A, B)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    -0.666139
-    (3,1)    -0.735859
-    (1,2)    -0.334348
-    (2,2)    -0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    -0.334348
-    (2,2)    0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-

But these give the same result

C1 = A-B
-C2 = GrB.eadd ('+', A, GrB.apply ('-', B))
-err = norm (C1-C2,1)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    -0.666139
-    (3,1)    -0.735859
-    (1,2)    -0.334348
-    (2,2)    -0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    -0.666139
-    (3,1)    -0.735859
-    (1,2)    -0.334348
-    (2,2)    -0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-err =
-     0
-

Element-wise 'multiplication'

For C = A.*B, the result C is the set intersection of the pattern of A and B. The operator is applied to entries in both A and B. Entries in A but not B, or B but not A, do not appear in the result C.

C1 = A.*B
-C2 = GrB.emult ('*', A, B)
-C3 = double (A) .* double (B)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  1 nonzero, 1 entry
-
-    (1,2)    0.518474
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  1 nonzero, 1 entry
-
-    (1,2)    0.518474
-
-C3 =
-   (1,2)       0.5185
-

Just as in GrB.eadd, any operator can be used in GrB.emult:

A
-B
-C2 = GrB.emult ('max', A, B)
-
-A =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,2)    0.572029
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-B =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    0.906378
-    (2,2)    0.146938
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  1 nonzero, 1 entry
-
-    (1,2)    0.906378
-
-

Overloaded operators

The following operators all work as you would expect for any matrix. The matrices A and B can be GraphBLAS matrices, or MATLAB sparse or dense matrices, in any combination, or scalars where appropriate:

  A+B   A-B  A*B   A.*B  A./B  A.\B  A.^b   A/b   C=A(I,J)
-  -A    +A   ~A    A'    A.'   A&B   A|B    b\A   C(I,J)=A
-  A~=B  A>B  A==B  A<=B  A>=B  A<B   [A,B]  [A;B]
-  A(1:end,1:end)

For A^b, b must be a non-negative integer.

C1 = [A B] ;
-C2 = [double(A) double(B)] ;
-assert (isequal (double (C1), C2))
-
C1 = A^2
-C2 = double (A)^2 ;
-err = norm (C1 - C2, 1)
-assert (err < 1e-12)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  5 nonzeros, 5 entries
-
-    (2,2)    0.140946
-    (3,2)    0.0590838
-    (1,3)    0.142227
-    (2,3)    0.0259144
-    (3,3)    0.151809
-
-err =
-     0
-
C1 = A (1:2,2:end)
-A = double (A) ;
-C2 = A (1:2,2:end) ;
-assert (isequal (double (C1), C2))
-
-C1 =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  2 nonzeros, 2 entries
-
-    (1,1)    0.572029
-    (2,2)    0.248635
-
-

Overloaded functions

Many MATLAB built-in functions can be used with GraphBLAS matrices:

A few differences with the built-in functions:

S = sparse (G)        % makes a copy of a GrB matrix
-F = full (G)          % adds explicit zeros, so numel(F)==nnz(F)
-F = full (G,type,id)  % adds explicit identity values to a GrB matrix
-disp (G, level)       % display a GrB matrix G; level=2 is the default.
-

In the list below, the first set of Methods are overloaded built-in methods. They are used as-is on GraphBLAS matrices, such as C=abs(G). The Static methods are prefixed with "GrB.", as in C = GrB.apply ( ... ).

methods GrB
-
-Methods for class GrB:
-
-GrB             ge              le              sparse          
-abs             graph           length          spfun           
-all             gt              logical         spones          
-amd             horzcat         lt              sprand          
-and             int16           max             sprandn         
-any             int32           min             sprandsym       
-assert          int64           minus           sprintf         
-bandwidth       int8            mldivide        sqrt            
-ceil            isa             mpower          subsasgn        
-colamd          isbanded        mrdivide        subsref         
-complex         isdiag          mtimes          sum             
-conj            isempty         ne              symamd          
-ctranspose      isequal         nnz             symrcm          
-diag            isfinite        nonzeros        times           
-digraph         isfloat         norm            transpose       
-disp            ishermitian     not             tril            
-display         isinf           numel           triu            
-dmperm          isinteger       nzmax           true            
-double          islogical       ones            uint16          
-eig             ismatrix        or              uint32          
-end             isnan           plus            uint64          
-eps             isnumeric       power           uint8           
-eq              isreal          prod            uminus          
-etree           isscalar        rdivide         uplus           
-false           issparse        real            vertcat         
-find            issymmetric     repmat          xor             
-fix             istril          reshape         zeros           
-flip            istriu          round           
-floor           isvector        sign            
-fprintf         kron            single          
-full            ldivide         size            
-
-Static methods:
-
-apply           emult           kronecker       select          
-assign          entries         ktruss          selectopinfo    
-bfs             expand          laplacian       semiringinfo    
-binopinfo       extract         mis             speye           
-build           extracttuples   monoidinfo      subassign       
-chunk           eye             mxm             threads         
-clear           format          nonz            trans           
-compact         incidence       offdiag         tricount        
-descriptorinfo  isbycol         pagerank        type            
-dnn             isbyrow         prune           unopinfo        
-eadd            isfull          random          vreduce         
-empty           issigned        reduce          
-
-

Zeros are handled differently

Explicit zeros cannot be automatically dropped from a GraphBLAS matrix, like they are in MATLAB sparse matrices. In a shortest-path problem, for example, an edge A(i,j) that is missing has an infinite weight, (the monoid identity of min(x,y) is +inf). A zero edge weight A(i,j)=0 is very different from an entry that is not present in A. However, if a GraphBLAS matrix is converted into a MATLAB sparse matrix, explicit zeros are dropped, which is the convention for a MATLAB sparse matrix. They can also be dropped from a GraphBLAS matrix using the GrB.select method.

G = GrB (magic (2)) ;
-G (1,1) = 0      % G(1,1) still appears as an explicit entry
-A = double (G)   % but it's dropped when converted to MATLAB sparse
-H = GrB.select ('nonzero', G)  % drops the explicit zeros from G
-fprintf ('nnz (G): %d  nnz (A): %g nnz (H): %g\n', ...
-    nnz (G), nnz (A), nnz (H)) ;
-fprintf ('num entries in G: %d\n', GrB.entries (G)) ;
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  3 nonzeros, 4 entries
-
-    (1,1)    0
-    (2,1)    4
-    (1,2)    3
-    (2,2)    2
-
-A =
-   (2,1)        4
-   (1,2)        3
-   (2,2)        2
-
-H =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  3 nonzeros, 3 entries
-
-    (2,1)    4
-    (1,2)    3
-    (2,2)    2
-
-nnz (G): 3  nnz (A): 3 nnz (H): 3
-num entries in G: 4
-

Displaying contents of a GraphBLAS matrix

Unlike MATLAB, the default is to display just a few entries of a GrB matrix. Here are all 100 entries of a 10-by-10 matrix, using a non-default disp(G,3):

G = GrB (rand (10)) ;
-% display everything:
-disp (G,3)
-
-G =
-
-  10x10 GraphBLAS double matrix, sparse by col:
-  100 nonzeros, 100 entries
-
-    (1,1)    0.0342763
-    (2,1)    0.17802
-    (3,1)    0.887592
-    (4,1)    0.889828
-    (5,1)    0.769149
-    (6,1)    0.00497062
-    (7,1)    0.735693
-    (8,1)    0.488349
-    (9,1)    0.332817
-    (10,1)    0.0273313
-    (1,2)    0.467212
-    (2,2)    0.796714
-    (3,2)    0.849463
-    (4,2)    0.965361
-    (5,2)    0.902248
-    (6,2)    0.0363252
-    (7,2)    0.708068
-    (8,2)    0.322919
-    (9,2)    0.700716
-    (10,2)    0.472957
-    (1,3)    0.204363
-    (2,3)    0.00931977
-    (3,3)    0.565881
-    (4,3)    0.183435
-    (5,3)    0.00843818
-    (6,3)    0.284938
-    (7,3)    0.706156
-    (8,3)    0.909475
-    (9,3)    0.84868
-    (10,3)    0.564605
-    (1,4)    0.075183
-    (2,4)    0.535293
-    (3,4)    0.072324
-    (4,4)    0.515373
-    (5,4)    0.926149
-    (6,4)    0.949252
-    (7,4)    0.0478888
-    (8,4)    0.523767
-    (9,4)    0.167203
-    (10,4)    0.28341
-    (1,5)    0.122669
-    (2,5)    0.441267
-    (3,5)    0.157113
-    (4,5)    0.302479
-    (5,5)    0.758486
-    (6,5)    0.910563
-    (7,5)    0.0246916
-    (8,5)    0.232421
-    (9,5)    0.38018
-    (10,5)    0.677531
-    (1,6)    0.869074
-    (2,6)    0.471459
-    (3,6)    0.624929
-    (4,6)    0.987186
-    (5,6)    0.282885
-    (6,6)    0.843833
-    (7,6)    0.869597
-    (8,6)    0.308209
-    (9,6)    0.201332
-    (10,6)    0.706603
-    (1,7)    0.563222
-    (2,7)    0.575795
-    (3,7)    0.056376
-    (4,7)    0.73412
-    (5,7)    0.608022
-    (6,7)    0.0400164
-    (7,7)    0.540801
-    (8,7)    0.023064
-    (9,7)    0.165682
-    (10,7)    0.250393
-    (1,8)    0.23865
-    (2,8)    0.232033
-    (3,8)    0.303191
-    (4,8)    0.579934
-    (5,8)    0.267751
-    (6,8)    0.916376
-    (7,8)    0.833499
-    (8,8)    0.978692
-    (9,8)    0.734445
-    (10,8)    0.102896
-    (1,9)    0.353059
-    (2,9)    0.738955
-    (3,9)    0.57539
-    (4,9)    0.751433
-    (5,9)    0.93256
-    (6,9)    0.281622
-    (7,9)    0.51302
-    (8,9)    0.24406
-    (9,9)    0.950086
-    (10,9)    0.303638
-    (1,10)    0.563593
-    (2,10)    0.705101
-    (3,10)    0.0604146
-    (4,10)    0.672065
-    (5,10)    0.359793
-    (6,10)    0.62931
-    (7,10)    0.977758
-    (8,10)    0.394328
-    (9,10)    0.765651
-    (10,10)    0.457809
-
-
-

That was disp(G,3), so every entry was printed. It's a little long, so the default is not to print everything.

With the default display (level = 2):

G
-
-G =
-
-  10x10 GraphBLAS double matrix, sparse by col:
-  100 nonzeros, 100 entries
-
-    (1,1)    0.0342763
-    (2,1)    0.17802
-    (3,1)    0.887592
-    (4,1)    0.889828
-    (5,1)    0.769149
-    (6,1)    0.00497062
-    (7,1)    0.735693
-    (8,1)    0.488349
-    (9,1)    0.332817
-    (10,1)    0.0273313
-    (1,2)    0.467212
-    (2,2)    0.796714
-    (3,2)    0.849463
-    (4,2)    0.965361
-    (5,2)    0.902248
-    (6,2)    0.0363252
-    (7,2)    0.708068
-    (8,2)    0.322919
-    (9,2)    0.700716
-    (10,2)    0.472957
-    (1,3)    0.204363
-    (2,3)    0.00931977
-    (3,3)    0.565881
-    (4,3)    0.183435
-    (5,3)    0.00843818
-    (6,3)    0.284938
-    (7,3)    0.706156
-    (8,3)    0.909475
-    (9,3)    0.84868
-    (10,3)    0.564605
-    ...
-
-

That was disp(G,2) or just display(G), which is what is printed by a MATLAB statement that doesn't have a trailing semicolon. With level = 1, disp(G,1) gives just a terse summary:

disp (G,1)
-
-G =
-
-  10x10 GraphBLAS double matrix, sparse by col:
-  100 nonzeros, 100 entries
-
-
-

Storing a matrix by row or by column

MATLAB stores its sparse matrices by column, refered to as 'standard CSC' in SuiteSparse:GraphBLAS. In the CSC (compressed sparse column) format, each column of the matrix is stored as a list of entries, with their value and row index. In the CSR (compressed sparse row) format, each row is stored as a list of values and their column indices. GraphBLAS uses both CSC and CSR, and the two formats can be intermixed arbitrarily. In its C interface, the default format is CSR. However, for better compatibility with MATLAB, this MATLAB interface for SuiteSparse:GraphBLAS uses CSC by default instead.

rng ('default') ;
-GrB.clear ;                      % clear all prior GraphBLAS settings
-fprintf ('the default format is: %s\n', GrB.format) ;
-C = sparse (rand (2))
-G = GrB (C)
-GrB.format (G)
-
the default format is: by col
-C =
-   (1,1)       0.8147
-   (2,1)       0.9058
-   (1,2)       0.1270
-   (2,2)       0.9134
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.814724
-    (2,1)    0.905792
-    (1,2)    0.126987
-    (2,2)    0.913376
-
-ans =
-    'by col'
-

Many graph algorithms work better in CSR format, with matrices stored by row. For example, it is common to use A(i,j) for the edge (i,j), and many graph algorithms need to access the out-adjacencies of nodes, which is the row A(i,;) for node i. If the CSR format is desired, GrB.format ('by row') tells GraphBLAS to create all subsequent matrices in the CSR format. Converting from a MATLAB sparse matrix (in standard CSC format) takes a little more time (requiring a transpose), but subsequent graph algorithms can be faster.

G = GrB (C, 'by row')
-fprintf ('the format of G is:    %s\n', GrB.format (G)) ;
-H = GrB (C)
-fprintf ('the format of H is:    %s\n', GrB.format (H)) ;
-err = norm (H-G,1)
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by row:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.814724
-    (1,2)    0.126987
-    (2,1)    0.905792
-    (2,2)    0.913376
-
-the format of G is:    by row
-
-H =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.814724
-    (2,1)    0.905792
-    (1,2)    0.126987
-    (2,2)    0.913376
-
-the format of H is:    by col
-err =
-     0
-

Hypersparse matrices

SuiteSparse:GraphBLAS can use two kinds of sparse matrix data structures: standard and hypersparse, for both CSC and CSR formats. In the standard CSC format used in MATLAB, an m-by-n matrix A takes O(n+nnz(A)) space. MATLAB can create huge column vectors, but not huge matrices (when n is huge).

clear all
-[c, huge] = computer ;
-C = sparse (huge, 1)    % MATLAB can create a huge-by-1 sparse column
-try
-    C = sparse (huge, huge)     % but this fails
-catch me
-    error_expected = me
-end
-
C =
-   All zero sparse: 281474976710655x1
-error_expected = 
-  MException with properties:
-
-    identifier: 'MATLAB:array:SizeLimitExceeded'
-       message: 'Requested 281474976710655x281474976710655 (2097152.0GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See <a href="matlab: helpview([docroot '/matlab/helptargets.map'], 'matlab_env_workspace_prefs')">array size limit</a> or preference panel for more information.'
-         cause: {0x1 cell}
-         stack: [4x1 struct]
-

In a GraphBLAS hypersparse matrix, an m-by-n matrix A takes only O(nnz(A)) space. The difference can be huge if nnz (A) << n.

clear
-[c, huge] = computer ;
-G = GrB (huge, 1)            % no problem for GraphBLAS
-H = GrB (huge, huge)         % this works in GraphBLAS too
-
-G =
-
-  281474976710655x1 GraphBLAS double matrix, sparse by col:
-  no nonzeros, no entries
-
-
-H =
-
-  281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
-  no nonzeros, no entries
-
-

Operations on huge hypersparse matrices are very fast; no component of the time or space complexity is Omega(n).

I = randperm (huge, 2) ;
-J = randperm (huge, 2) ;
-H (I,J) = magic (2) ;        % add 4 nonzeros to random locations in H
-H (I,I) = 10 * [1 2 ; 3 4] ; % so H^2 is not all zero
-H = H^2 ;                    % square H
-H = (H' * 2) ;               % transpose H and double the entries
-K = pi * spones (H) ;
-H = H + K                    % add pi to each entry in H
-
-H =
-
-  281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
-  8 nonzeros, 8 entries
-
-    (27455183225557,27455183225557)    4403.14
-    (78390279669562,27455183225557)    383.142
-    (153933462881710,27455183225557)    343.142
-    (177993304104065,27455183225557)    3003.14
-    (27455183225557,177993304104065)    2003.14
-    (78390279669562,177993304104065)    183.142
-    (153933462881710,177993304104065)    143.142
-    (177993304104065,177993304104065)    1403.14
-
-

numel uses vpa if the matrix is really huge

e1 = numel (G)               % this is huge, but still a flint
-e2 = numel (H)               % this is huge^2, which needs vpa
-whos e1 e2
-
e1 =
-   2.8147e+14
-e2 =
-79228162514263774643590529025.0
-  Name      Size            Bytes  Class     Attributes
-
-  e1        1x1                 8  double              
-  e2        1x1                 8  sym                 
-
-

All of these matrices take very little memory space:

whos C G H K
-
  Name                    Size                         Bytes  Class    Attributes
-
-  G         281474976710655x1                            989  GrB                
-  H         281474976710655x281474976710655             1308  GrB                
-  K         281474976710655x281474976710655             1308  GrB                
-
-

The mask and accumulator

When not used in overloaded operators or built-in functions, many GraphBLAS methods of the form GrB.method ( ... ) can optionally use a mask and/or an accumulator operator. If the accumulator is '+' in GrB.mxm, for example, then C = C + A*B is computed. The mask acts much like logical indexing in MATLAB. With a logical mask matrix M, C<M>=A*B allows only part of C to be assigned. If M(i,j) is true, then C(i,j) can be modified. If false, then C(i,j) is not modified.

For example, to set all values in C that are greater than 0.5 to 3:

A = rand (3)
-C = GrB.assign (A, A > 0.5, 3) ;     % in GraphBLAS
-C1 = GrB (A) ; C1 (A > .5) = 3       % also in GraphBLAS
-C2 = A      ; C2 (A > .5) = 3       % in MATLAB
-err = norm (C - C1, 1)
-err = norm (C - C2, 1)
-
A =
-    0.9575    0.9706    0.8003
-    0.9649    0.9572    0.1419
-    0.1576    0.4854    0.4218
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)    3
-    (2,1)    3
-    (3,1)    0.157613
-    (1,2)    3
-    (2,2)    3
-    (3,2)    0.485376
-    (1,3)    3
-    (2,3)    0.141886
-    (3,3)    0.421761
-
-C2 =
-    3.0000    3.0000    3.0000
-    3.0000    3.0000    0.1419
-    0.1576    0.4854    0.4218
-err =
-     0
-err =
-     0
-

The descriptor

Most GraphBLAS functions of the form GrB.method ( ... ) take an optional last argument, called the descriptor. It is a MATLAB struct that can modify the computations performed by the method. 'help GrB.descriptorinfo' gives all the details. The following is a short summary of the primary settings:

d.out = 'default' or 'replace', clears C after the accum op is used.

d.mask = 'default' or 'complement', to use M or ~M as the mask matrix.

d.in0 = 'default' or 'transpose', to transpose A for C=A*B, C=A+B, etc.

d.in1 = 'default' or 'transpose', to transpose B for C=A*B, C=A+B, etc.

d.kind = 'default', 'GrB', 'sparse', or 'full'; the output of GrB.method.

A = sparse (rand (2)) ;
-B = sparse (rand (2)) ;
-C1 = A'*B ;
-C2 = GrB.mxm ('+.*', A, B, struct ('in0', 'transpose')) ;
-err = norm (C1-C2,1)
-
err =
-     0
-

Integer arithmetic is different in GraphBLAS

MATLAB supports integer arithmetic on its full matrices, using int8, int16, int32, int64, uint8, uint16, uint32, or uint64 data types. None of these integer data types can be used to construct a MATLAB sparse matrix, which can only be double, double complex, or logical. Furthermore, C=A*B is not defined for integer types in MATLAB, except when A and/or B are scalars.

GraphBLAS supports all of those types for its sparse matrices (except for complex, which will be added in the future). All operations are supported, including C=A*B when A or B are any integer type, for all 1,865 semirings (1,040 of which are unique).

However, integer arithmetic differs in GraphBLAS and MATLAB. In MATLAB, integer values saturate if they exceed their maximum value. In GraphBLAS, integer operators act in a modular fashion. The latter is essential when computing C=A*B over a semiring. A saturating integer operator cannot be used as a monoid since it is not associative.

The C API for GraphBLAS allows for the creation of arbitrary user-defined types, so it would be possible to create different binary operators to allow element-wise integer operations to saturate, perhaps:

C = GrB.eadd('+saturate',A,B)
-

This would require an extension to this MATLAB interface.

C = uint8 (magic (3)) ;
-G = GrB (C) ;
-C1 = C * 40
-C2 = G * 40
-C3 = double (G) * 40 ;
-S = double (C1 < 255) ;
-assert (isequal (double (C1).*S, double (C2).*S))
-assert (isequal (nonzeros (C2), double (mod (nonzeros (C3), 256))))
-
C1 =
-  3x3 uint8 matrix
-   255    40   240
-   120   200   255
-   160   255    80
-
-C2 =
-
-  3x3 GraphBLAS uint8_t matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)   64
-    (2,1)   120
-    (3,1)   160
-    (1,2)   40
-    (2,2)   200
-    (3,2)   104
-    (1,3)   240
-    (2,3)   24
-    (3,3)   80
-
-

An example graph algorithm: breadth-first search

The breadth-first search of a graph finds all nodes reachable from the source node, and their level, v. v=GrB.bfs(A,s) or v=bfs_matlab(A,s) compute the same thing, but GrB.bfs uses GraphBLAS matrices and operations, while bfs_matlab uses pure MATLAB operations. v is defined as v(s) = 1 for the source node, v(i) = 2 for nodes adjacent to the source, and so on.

clear all
-rng ('default') ;
-n = 1e5 ;
-A = logical (sprandn (n, n, 1e-3)) ;
-
-tic
-v1 = GrB.bfs (A, 1) ;
-gb_time = toc ;
-
-tic
-v2 = bfs_matlab (A, 1) ;
-matlab_time = toc ;
-
-assert (isequal (double (v1'), v2))
-fprintf ('\nnodes reached: %d of %d\n', nnz (v2), n) ;
-fprintf ('GraphBLAS time: %g sec\n', gb_time) ;
-fprintf ('MATLAB time:    %g sec\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
-nodes reached: 100000 of 100000
-GraphBLAS time: 0.405309 sec
-MATLAB time:    1.11767 sec
-Speedup of GraphBLAS over MATLAB: 2.75757
-

Example graph algorithm: Luby's method in GraphBLAS

The GrB.mis.m function is variant of Luby's randomized algorithm [Luby 1985]. It is a parallel method for finding an maximal independent set of nodes, where no two nodes are adjacent. See the GraphBLAS/@GrB/GrB.mis.m function for details. The graph must be symmetric with a zero-free diagonal, so A is symmetrized first and any diagonal entries are removed.

A = GrB (A) ;
-A = GrB.offdiag (A|A') ;
-
-tic
-s = GrB.mis (A) ;
-toc
-fprintf ('# nodes in the graph: %g\n', size (A,1)) ;
-fprintf ('# edges: : %g\n', GrB.entries (A) / 2) ;
-fprintf ('size of maximal independent set found: %g\n', ...
-    full (double (sum (s)))) ;
-
-% make sure it's independent
-p = find (s) ;
-S = A (p,p) ;
-assert (GrB.entries (S) == 0)
-
-% make sure it's maximal
-notp = find (s == 0) ;
-S = A (notp, p) ;
-deg = GrB.vreduce ('+.int64', S) ;
-assert (logical (all (deg > 0)))
-
Elapsed time is 0.357480 seconds.
-# nodes in the graph: 100000
-# edges: : 9.9899e+06
-size of maximal independent set found: 2811
-

Sparse deep neural network

The 2019 MIT GraphChallenge (see http://graphchallenge.org) is to solve a set of large sparse deep neural network problems. In this demo, the MATLAB reference solution is compared with a solution using GraphBLAS, for a randomly constructed neural network. See the GrB.dnn and dnn_matlab.m functions for details.

clear all
-rng ('default') ;
-nlayers = 16 ;
-nneurons = 4096 ;
-nfeatures = 30000 ;
-fprintf ('# layers:   %d\n', nlayers) ;
-fprintf ('# neurons:  %d\n', nneurons) ;
-fprintf ('# features: %d\n', nfeatures) ;
-
-tic
-Y0 = sprand (nfeatures, nneurons, 0.1) ;
-for layer = 1:nlayers
-    W {layer} = sprand (nneurons, nneurons, 0.01) * 0.2 ;
-    bias {layer} = -0.2 * ones (1, nneurons) ;
-end
-t_setup = toc ;
-fprintf ('construct problem time: %g sec\n', t_setup) ;
-
-% convert the problem from MATLAB to GraphBLAS
-t = tic ;
-[W_gb, bias_gb, Y0_gb] = dnn_mat2gb (W, bias, Y0) ;
-t = toc (t) ;
-fprintf ('setup time: %g sec\n', t) ;
-
# layers:   16
-# neurons:  4096
-# features: 30000
-construct problem time: 7.8231 sec
-setup time: 0.203018 sec
-

Solving the sparse deep neural network problem with GraphbLAS

Please wait ...

tic
-Y1 = GrB.dnn (W_gb, bias_gb, Y0_gb) ;
-gb_time = toc ;
-fprintf ('total time in GraphBLAS: %g sec\n', gb_time) ;
-
total time in GraphBLAS: 5.17587 sec
-

Solving the sparse deep neural network problem with MATLAB

Please wait ...

tic
-Y2 = dnn_matlab (W, bias, Y0) ;
-matlab_time = toc ;
-fprintf ('total time in MATLAB:    %g sec\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
-err = norm (Y1-Y2,1)
-
total time in MATLAB:    128.418 sec
-Speedup of GraphBLAS over MATLAB: 24.8109
-err =
-     0
-

For objects, GraphBLAS has better colon notation than MATLAB

The MATLAB notation C = A (start:inc:fini) is very handy, and it works great if A is a MATLAB matrix. But for objects like the GraphBLAS matrix, MATLAB starts by creating the explicit index vector I = start:inc:fini. That's fine if the matrix is modest in size, but GraphBLAS can construct huge matrices. The problem is that 1:n cannot be explicitly constructed when n is huge.

The C API for GraphBLAS can represent the colon notation start:inc:fini in an implicit manner, so it can do the indexing without actually forming the explicit list I = start:inc:fini. But there is no access to this method using the MATLAB notation start:inc:fini.

Thus, to compute C = A (start:inc:fini) for very huge matrices, you need to use use a cell array to represent the colon notation, as { start, inc, fini }, instead of start:inc:fini. See 'help GrB.extract' and 'help.gbsubassign' for, for C(I,J)=A. The syntax isn't conventional, but it is far faster than the MATLAB colon notation for objects, and takes far less memory when I is huge.

n = 1e14 ;
-H = GrB (n, n) ;            % a huge empty matrix
-I = [1 1e9 1e12 1e14] ;
-M = magic (4)
-H (I,I) = M ;
-J = {1, 1e13} ;            % represents 1:1e13 colon notation
-C1 = H (J, J)              % computes C1 = H (1:e13,1:1e13)
-c = nonzeros (C1) ;
-m = nonzeros (M (1:3, 1:3)) ;
-assert (isequal (c, m)) ;
-
M =
-    16     2     3    13
-     5    11    10     8
-     9     7     6    12
-     4    14    15     1
-
-C1 =
-
-  10000000000000x10000000000000 GraphBLAS double matrix, hypersparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)    16
-    (1000000000,1)    5
-    (1000000000000,1)    9
-    (1,1000000000)    2
-    (1000000000,1000000000)    11
-    (1000000000000,1000000000)    7
-    (1,1000000000000)    3
-    (1000000000,1000000000000)    10
-    (1000000000000,1000000000000)    6
-
-
try
-    % try to compute the same thing with colon
-    % notation (1:1e13), but this fails:
-    C2 = H (1:1e13, 1:1e13)
-catch me
-    error_expected = me
-end
-
error_expected = 
-  MException with properties:
-
-    identifier: 'MATLAB:array:SizeLimitExceeded'
-       message: 'Requested 10000000000000x1 (74505.8GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See <a href="matlab: helpview([docroot '/matlab/helptargets.map'], 'matlab_env_workspace_prefs')">array size limit</a> or preference panel for more information.'
-         cause: {}
-         stack: [4x1 struct]
-

Iterative solvers work as-is

Many built-in functions work with GraphBLAS matrices unmodified.

A = sparse (rand (4)) ;
-b = sparse (rand (4,1)) ;
-x = gmres (A,b)
-norm (A*x-b)
-x = gmres (GrB(A), GrB(b))
-norm (A*x-b)
-
gmres converged at iteration 4 to a solution with relative residual 0.
-x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
-ans =
-   8.6711e-16
-gmres converged at iteration 4 to a solution with relative residual 0.
-x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
-ans =
-   7.2802e-16
-

... even in single precision

x = gmres (GrB(A,'single'), GrB(b,'single'))
-norm (A*x-b)
-
gmres converged at iteration 4 to a solution with relative residual 0.
-x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
-ans =
-   3.6346e-07
-

Both of the following uses of minres (A,b) fail to converge because A is not symmetric, as the method requires. Both failures are correctly reported, and both the MATLAB version and the GraphBLAS version return the same incorrect vector x.

x = minres (A, b)
-x = minres (GrB(A), GrB(b))
-
minres stopped at iteration 4 without converging to the desired tolerance 1e-06
-because the maximum number of iterations was reached.
-The iterate returned (number 4) has relative residual 0.21.
-x =
-    0.2489
-    0.2081
-    0.0700
-    0.3928
-minres stopped at iteration 4 without converging to the desired tolerance 1e-06
-because the maximum number of iterations was reached.
-The iterate returned (number 4) has relative residual 0.21.
-
-x =
-
-  4x1 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.248942
-    (2,1)    0.208128
-    (3,1)    0.0699707
-    (4,1)    0.392812
-
-

With a proper symmetric matrix

A = A+A' ;
-x = minres (A, b)
-norm (A*x-b)
-x = minres (GrB(A), GrB(b))
-norm (A*x-b)
-
minres converged at iteration 4 to a solution with relative residual 1.3e-11.
-x =
- -114.0616
-   -1.4211
-  134.8227
-    2.0694
-ans =
-   1.3650e-11
-minres converged at iteration 4 to a solution with relative residual 1.3e-11.
-
-x =
-
-  4x1 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    -114.062
-    (2,1)    -1.4211
-    (3,1)    134.823
-    (4,1)    2.0694
-
-ans =
-   1.3650e-11
-

Extreme performance differences between GraphBLAS and MATLAB.

The GraphBLAS operations used so far are perhaps 2x to 50x faster than the corresponding MATLAB operations, depending on how many cores your computer has. To run a demo illustrating a 500x or more speedup versus MATLAB, run this demo:

  gbdemo2

It will illustrate an assignment C(I,J)=A that can take under a second in GraphBLAS but several minutes in MATLAB. To make the comparsion even more dramatic, try:

  gbdemo2 (20000)

assuming you have enough memory. The gbdemo2 is not part of this demo since it can take a long time; it tries a range of problem sizes, and each one takes several minutes in MATLAB.

Sparse logical indexing is much, much faster in GraphBLAS

The mask in GraphBLAS acts much like logical indexing in MATLAB, but it is not quite the same. MATLAB logical indexing takes the form:

     C (M) = A (M)

which computes the same thing as the GraphBLAS statement:

     C = GrB.assign (C, M, A)

The GrB.assign statement computes C(M)=A(M), and it is vastly faster than C(M)=A(M), even if the time to convert the GrB matrix back to a MATLAB sparse matrix is included.

GraphBLAS can also compute C (M) = A (M) using overloaded operators for subsref and subsasgn, but C = GrB.assign (C, M, A) is a bit faster.

First, both methods in GraphBLAS (both are very fast):

clear
-n = 4000 ;
-tic
-C = sprand (n, n, 0.1) ;
-A = 100 * sprand (n, n, 0.1) ;
-M = (C > 0.5) ;
-t_setup = toc ;
-fprintf ('nnz(C): %g, nnz(M): %g, nnz(A): %g\n', ...
-    nnz(C), nnz(M), nnz(A)) ;
-fprintf ('\nsetup time:     %g sec\n', t_setup) ;
-
-% include the time to convert C1 from a GraphBLAS
-% matrix to a MATLAB sparse matrix:
-tic
-C1 = GrB.assign (C, M, A) ;
-C1 = double (C1) ;
-gb_time = toc ;
-fprintf ('\nGraphBLAS time: %g sec for GrB.assign\n', gb_time) ;
-
-% now using overloaded operators, also include the time to
-% convert back to a MATLAB sparse matrix, for good measure:
-A2 = GrB (A) ;
-C2 = GrB (C) ;
-tic
-C2 (M) = A2 (M) ;
-C2 = double (C2) ;
-gb_time2 = toc ;
-fprintf ('\nGraphBLAS time: %g sec for C(M)=A(M)\n', gb_time2) ;
-
nnz(C): 1.5226e+06, nnz(M): 761163, nnz(A): 1.52245e+06
-
-setup time:     1.23474 sec
-
-GraphBLAS time: 0.029719 sec for GrB.assign
-
-GraphBLAS time: 0.053027 sec for C(M)=A(M)
-

Please wait, this will take about 10 minutes or so ...

tic
-C (M) = A (M) ;
-matlab_time = toc ;
-
-fprintf ('\nGraphBLAS time: %g sec (GrB.assign)\n', gb_time) ;
-fprintf ('\nGraphBLAS time: %g sec (overloading)\n', gb_time2) ;
-fprintf ('MATLAB time:    %g sec\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time2) ;
-
-% GraphBLAS computes the exact same result with both methods:
-assert (isequal (C1, C))
-assert (isequal (C2, C))
-C1 - C
-C2 - C
-
-GraphBLAS time: 0.029719 sec (GrB.assign)
-
-GraphBLAS time: 0.053027 sec (overloading)
-MATLAB time:    1110.79 sec
-Speedup of GraphBLAS over MATLAB: 20947.7
-ans =
-   All zero sparse: 4000x4000
-ans =
-   All zero sparse: 4000x4000
-

Limitations and their future solutions

The MATLAB interface for SuiteSparse:GraphBLAS is a work-in-progress. It has some limitations, most of which will be resolved over time.

(1) Nonblocking mode:

GraphBLAS has a 'non-blocking' mode, in which operations can be left pending and completed later. SuiteSparse:GraphBLAS uses the non-blocking mode to speed up a sequence of assignment operations, such as C(I,J)=A. However, in its MATLAB interface, this would require a MATLAB mexFunction to modify its inputs. That breaks the MATLAB API standard, so it cannot be safely done. As a result, using GraphBLAS via its MATLAB interface can be slower than when using its C API. This restriction would not be a limitation if GraphBLAS were to be incorporated into MATLAB itself, but there is likely no way to do this in a mexFunction interface to GraphBLAS.

(2) Complex matrices:

GraphBLAS can operate on matrices with arbitrary user-defined types and operators. The only constraint is that the type be a fixed sized typedef that can be copied with the ANSI C memcpy; variable-sized types are not yet supported. However, in this MATLAB interface, SuiteSparse:GraphBLAS has access to only predefined types, operators, and semirings. Complex types and operators will be added to this MATLAB interface in the future. They already appear in the C version of GraphBLAS, with user-defined operators in GraphBLAS/Demo/Source/usercomplex.c.

(3) Integer element-wise operations:

Integer operations in MATLAB saturate, so that uint8(255)+1 is 255. To allow for integer monoids, GraphBLAS uses modular arithmetic instead. This is the only way that C=A*B can be defined for integer semirings. However, saturating integer operators could be added in the future, so that element- wise integer operations on GraphBLAS sparse integer matrices could work just the same as their MATLAB counterparts.

So in the future, you could perhaps write this, for both sparse and dense integer matrices A and B:

     C = GrB.eadd ('+saturate.int8', A, B)

to compute the same thing as C=A+B in MATLAB for its full int8 matrices. Note that MATLAB can do this only for dense integer matrices, since it doesn't support sparse integer matrices.

(4) Faster methods:

Most methods in this MATLAB interface are based on efficient parallel C functions in GraphBLAS itself, and are typically as fast or faster than the equivalent built-in operators and functions in MATLAB.

There are few notable exceptions; these will be addressed in the future. Dense matrices and vectors held as GraphBLAS objects are slower than their MATLAB counterparts. horzcat and vertcat, for [A B] and [A;B] when either A or B are GraphBLAS matrices, are also slow, as illustrated below in the next example.

Other methods that will be faster in the future include bandwidth, istriu, istril, eps, ceil, floor, round, fix, isfinite, isinf, isnan, spfun, and A.^B. These methods are currently implemented in m-files, not in efficient parallel C functions.

Here is an example that illustrates the performance of C = [A B]

clear
-A = sparse (rand (2000)) ;
-B = sparse (rand (2000)) ;
-tic
-C1 = [A B] ;
-matlab_time = toc ;
-
-A = GrB (A) ;
-B = GrB (B) ;
-tic
-C2 = [A B] ;
-gb_time = toc ;
-
-err = norm (C1-C2,1)
-fprintf ('\nMATLAB: %g sec, GraphBLAS: %g sec\n', ...
-    matlab_time, gb_time) ;
-if (gb_time > matlab_time)
-    fprintf ('GraphBLAS is slower by a factor of %g\n', ...
-        gb_time / matlab_time) ;
-end
-
err =
-     0
-
-MATLAB: 0.070933 sec, GraphBLAS: 0.207701 sec
-GraphBLAS is slower by a factor of 2.92813
-

(5) Linear indexing:

If A is an m-by-n 2D MATLAB matrix, with n > 1, A(:) is a column vector of length m*n. The index operation A(i) accesses the ith entry in the vector A(:). This is called linear indexing in MATLAB. It is not yet available for GraphBLAS matrices in this MATLAB interface to GraphBLAS, but it could be added in the future.

(6) Implicit singleton dimension expansion

In MATLAB C=A+B where A is m-by-n and B is a 1-by-n row vector implicitly expands B to a matrix, computing C(i,j)=A(i,j)+B(j). This implicit expansion is not yet suported in GraphBLAS with C=A+B. However, it can be done with C = GrB.mxm ('+.+', A, diag(GrB(B))). That's an nice example of the power of semirings, but it's not immediately obvious, and not as clear a syntax as C=A+B. The GraphBLAS/@GrB/dnn.m function uses this 'plus.plus' semiring to apply the bias to each neuron.

A = magic (3)
-B = 1000:1000:3000
-C1 = A + B
-C2 = GrB.mxm ('+.+', A, diag (GrB (B)))
-err = norm (C1-C2,1)
-
A =
-     8     1     6
-     3     5     7
-     4     9     2
-B =
-        1000        2000        3000
-C1 =
-        1008        2001        3006
-        1003        2005        3007
-        1004        2009        3002
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)    1008
-    (2,1)    1003
-    (3,1)    1004
-    (1,2)    2001
-    (2,2)    2005
-    (3,2)    2009
-    (1,3)    3006
-    (2,3)    3007
-    (3,3)    3002
-
-err =
-     0
-

GraphBLAS operations

In addition to the overloaded operators (such as C=A*B) and overloaded functions (such as L=tril(A)), GraphBLAS also has methods of the form GrB.method, listed on the next page. Most of them take an optional input matrix Cin, which is the initial value of the matrix C for the expression below, an optional mask matrix M, and an optional accumulator operator.

    C<#M,replace> = accum (C, T)

In the above expression, #M is either empty (no mask), M (with a mask matrix) or ~M (with a complemented mask matrix), as determined by the descriptor. 'replace' can be used to clear C after it is used in accum(C,T) but before it is assigned with C<...> = Z, where Z=accum(C,T). The matrix T is the result of some operation, such as T=A*B for GrB.mxm, or T=op(A,B) for GrB.eadd.

A summary of these GrB.methods is on the next pages.

Methods for the GrB class:

These methods operate on GraphBLAS matrices only, and they overload
-the existing MATLAB functions of the same name.
-
C = GrB (...)           construct a GraphBLAS matrix
-C = sparse (G)          makes a copy of a GrB matrix
-C = full (G, ...)       adds explicit zeros or id values to a GrB matrix
-C = double (G)          cast GrB matrix to MATLAB sparse double matrix
-C = logical (G)         cast GrB matrix to MATLAB sparse logical matrix
-C = complex (G)         cast GrB matrix to MATLAB sparse complex
-C = single (G)          cast GrB matrix to MATLAB full single matrix
-C = int8 (G)            cast GrB matrix to MATLAB full int8 matrix
-C = int16 (G)           cast GrB matrix to MATLAB full int16 matrix
-C = int32 (G)           cast GrB matrix to MATLAB full int32 matrix
-C = int64 (G)           cast GrB matrix to MATLAB full int64 matrix
-C = uint8 (G)           cast GrB matrix to MATLAB full uint8 matrix
-C = uint16 (G)          cast GrB matrix to MATLAB full uint16 matrix
-C = uint32 (G)          cast GrB matrix to MATLAB full uint32 matrix
-C = uint64 (G)          cast GrB matrix to MATLAB full uint64 matrix
-C = cast (G,...)        cast GrB matrix to MATLAB matrix (as above)
-
X = nonzeros (G)        extract all entries from a GrB matrix
-[I,J,X] = find (G)      extract all entries from a GrB matrix
-C = spones (G)          return pattern of GrB matrix
-disp (G, level)         display a GrB matrix G
-display (G)             display a GrB matrix G; same as disp(G,2)
-mn = numel (G)          m*n for an m-by-n GrB matrix G
-e = nnz (G)             number of entries in a GrB matrix G
-e = nzmax (G)           number of entries in a GrB matrix G
-[m n] = size (G)        size of a GrB matrix G
-n = length (G)          length of a GrB vector
-s = isempty (G)         true if any dimension of G is zero
-s = issparse (G)        true for any GrB matrix G
-s = ismatrix (G)        true for any GrB matrix G
-s = isvector (G)        true if m=1 or n=1, for an m-by-n GrB matrix G
-s = iscolumn (G)        true if n=1, for an m-by-n GrB matrix G
-s = isrow (G)           true if m=1, for an m-by-n GrB matrix G
-s = isscalar (G)        true if G is a 1-by-1 GrB matrix
-s = isnumeric (G)       true for any GrB matrix G (even logical)
-s = isfloat (G)         true if GrB matrix is double, single, complex
-s = isreal (G)          true if GrB matrix is not complex
-s = isinteger (G)       true if GrB matrix is int8, int16, ..., uint64
-s = islogical (G)       true if GrB matrix is logical
-s = isa (G, classname)  check if a GrB matrix is of a specific class
-
C = diag (G,k)          diagonal matrices and diagonals of GrB matrix G
-L = tril (G,k)          lower triangular part of GrB matrix G
-U = triu (G,k)          upper triangular part of GrB matrix G
-C = kron (A,B)          Kronecker product
-C = repmat (G, ...)     replicate and tile a GraphBLAS matrix
-C = reshape (G, ...)    reshape a GraphBLAS matrix
-C = abs (G)             absolute value
-C = sign (G)            signum function
-s = istril (G)          true if G is lower triangular
-s = istriu (G)          true if G is upper triangular
-s = isbanded (G,...)    true if G is banded
-s = isdiag (G)          true if G is diagonal
-s = ishermitian (G)     true if G is Hermitian
-s = issymmetric (G)     true if G is symmetric
-[lo,hi] = bandwidth (G) determine the lower & upper bandwidth of G
-C = sum (G, option)     reduce via sum, to vector or scalar
-C = prod (G, option)    reduce via product, to vector or scalar
-s = norm (G, kind)      1-norm or inf-norm of a GrB matrix
-C = max (G, ...)        reduce via max, to vector or scalar
-C = min (G, ...)        reduce via min, to vector or scalar
-C = any (G, ...)        reduce via '|', to vector or scalar
-C = all (G, ...)        reduce via '&', to vector or scalar
-
C = sqrt (G)            element-wise square root
-C = eps (G)             floating-point spacing
-C = ceil (G)            round towards infinity
-C = floor (G)           round towards -infinity
-C = round (G)           round towards nearest
-C = fix (G)             round towards zero
-C = isfinite (G)        test if finite
-C = isinf (G)           test if infinite
-C = isnan (G)           test if NaN
-C = spfun (fun, G)      evaluate a function on the entries of G
-p = amd (G)             approximate minimum degree ordering
-p = colamd (G)          column approximate minimum degree ordering
-p = symamd (G)          approximate minimum degree ordering
-p = symrcm (G)          reverse Cuthill-McKee ordering
-[...] = dmperm (G)      Dulmage-Mendelsohn permutation
-parent = etree (G)      elimination tree
-C = conj (G)            complex conjugate
-C = real (G)            real part of a complex GraphBLAS matrix
-[V, ...] = eig (G,...)  eigenvalues and eigenvectors
-assert (G)              generate an error if G is false
-C = zeros (...,'like',G)   all-zero matrix, same type as G
-C = false (...,'like',G)   all-false logical matrix
-C = ones (...,'like',G)    matrix with all ones, same type as G
-

Operator overloading:

C = plus (A, B)         C = A + B
-C = minus (A, B)        C = A - B
-C = uminus (G)          C = -G
-C = uplus (G)           C = +G
-C = times (A, B)        C = A .* B
-C = mtimes (A, B)       C = A * B
-C = rdivide (A, B)      C = A ./ B
-C = ldivide (A, B)      C = A .\ B
-C = mrdivide (A, B)     C = A / B
-C = mldivide (A, B)     C = A \ B
-C = power (A, B)        C = A .^ B
-C = mpower (A, B)       C = A ^ B
-C = lt (A, B)           C = A < B
-C = gt (A, B)           C = A > B
-C = le (A, B)           C = A <= B
-C = ge (A, B)           C = A >= B
-C = ne (A, B)           C = A ~= B
-C = eq (A, B)           C = A == B
-C = and (A, B)          C = A & B
-C = or (A, B)           C = A | B
-C = not (G)             C = ~G
-C = ctranspose (G)      C = G'
-C = transpose (G)       C = G.'
-C = horzcat (A, B)      C = [A , B]
-C = vertcat (A, B)      C = [A ; B]
-C = subsref (A, I, J)   C = A (I,J) or C = A (M)
-C = subsasgn (A, I, J)  C (I,J) = A
-index = end (A, k, n)   for object indexing, A(1:end,1:end)
-

Static Methods:

The Static Methods for the GrB class can be used on input matrices of
-any kind: GraphBLAS sparse matrices, MATLAB sparse matrices, or
-MATLAB dense matrices, in any combination.  The output matrix Cout is
-a GraphBLAS matrix, by default, but can be optionally returned as a
-MATLAB sparse or dense matrix.  The static methods divide into two
-categories: those that perform basic functions, and the GraphBLAS
-operations that use the mask/accum.
-

GraphBLAS basic functions:

GrB.clear                    clear GraphBLAS workspace and settings
-GrB.descriptorinfo (d)       list properties of a descriptor
-GrB.unopinfo (op, type)      list properties of a unary operator
-GrB.binopinfo (op, type)     list properties of a binary operator
-GrB.monoidinfo (op, type)    list properties of a monoid
-GrB.semiringinfo (s, type)   list properties of a semiring
-t = GrB.threads (t)          set/get # of threads to use in GraphBLAS
-c = GrB.chunk (c)            set/get chunk size to use in GraphBLAS
-result = GrB.entries (G,...) count or query entries in a matrix
-result = GrB.nonz (G,...)    count or query nonzeros in a matrix
-C = GrB.prune (A, id)        prune entries equal to id
-C = GrB.offdiag (A)          prune diagonal entries
-s = GrB.isfull (A)           true if all entries present
-[C,I,J] = GrB.compact (A,id) remove empty rows and columns
-G = GrB.empty (m, n)         return an empty GraphBLAS matrix
-s = GrB.type (A)             get the type of a MATLAB or GrB matrix A
-s = GrB.issigned (type)      true if type is signed
-f = GrB.format (f)           set/get matrix format to use in GraphBLAS
-s = GrB.isbyrow (A)          true if format f A is 'by row'
-s = GrB.isbycol (A)          true if format f A is 'by col'
-C = GrB.expand (scalar, A)   expand a scalar (C = scalar*spones(A))
-C = GrB.eye                  identity matrix of any type
-C = GrB.speye                identity matrix (of type 'double')
-C = GrB.build (I, J, X, m, n, dup, type, desc)
-                             build a GrB matrix from list of entries
-[I,J,X] = GrB.extracttuples (A, desc)
-                             extract all entries from a matrix
-

GraphBLAS operations with Cout, mask M, and accum.

Cout = GrB.mxm (Cin, M, accum, semiring, A, B, desc)
-                sparse matrix-matrix multiplication over a semiring
-Cout = GrB.select (Cin, M, accum, op, A, b, desc)
-                select a subset of entries from a matrix
-Cout = GrB.assign (Cin, M, accum, A, I, J, desc)
-                sparse matrix assignment, such as C(I,J)=A
-Cout = GrB.subassign (Cin, M, accum, A, I, J, desc)
-                sparse matrix assignment, such as C(I,J)=A
-Cout = GrB.vreduce (Cin, M, accum, op, A, desc)
-                reduce a matrix to a vector
-Cout = GrB.reduce (Cin, accum, op, A, desc)
-                reduce a matrix to a scalar
-Cout = GrB.kronecker (Cin, M, accum, op, A, B, desc)
-                Kronecker product
-Cout = GrB.trans (Cin, M, accum, A, desc)
-                transpose a matrix
-Cout = GrB.eadd (Cin, M, accum, op, A, B, desc)
-                element-wise addition
-Cout = GrB.emult (Cin, M, accum, op, A, B, desc)
-                element-wise multiplication
-Cout = GrB.apply (Cin, M, accum, op, A, desc)
-                apply a unary operator
-Cout = GrB.extract (Cin, M, accum, A, I, J, desc)
-                extract submatrix, like C=A(I,J) in MATLAB
-

GraphBLAS operations (with Cout, Cin arguments) take the following form:

C<#M,replace> = accum (C, operation (A or A', B or B'))
-
C is both an input and output matrix.  In this MATLAB interface to
-GraphBLAS, it is split into Cin (the value of C on input) and Cout
-(the value of C on output).  M is the optional mask matrix, and #M is
-either M or !M depending on whether or not the mask is complemented
-via the desc.mask option.  The replace option is determined by
-desc.out; if present, C is cleared after it is used in the accum
-operation but before the final assignment.  A and/or B may optionally
-be transposed via the descriptor fields desc.in0 and desc.in1,
-respectively.  To select the format of Cout, use desc.format.  See
-GrB.descriptorinfo for more details.
-
accum is optional; if not is not present, then the operation becomes
-C<...> = operation(A,B).  Otherwise, C = C + operation(A,B) is
-computed where '+' is the accum operator.  It acts like a sparse
-matrix addition (see GrB.eadd), in terms of the structure of the
-result C, but any binary operator can be used.
-
The mask M acts like MATLAB logical indexing.  If M(i,j)=1 then
-C(i,j) can be modified; if zero, it cannot be modified by the
-operation.
-

Static Methods for graph algorithms:

r = GrB.pagerank (A, opts) ;            % PageRank of a matrix
-C = GrB.ktruss (A, k, check) ;          % k-truss
-s = GrB.tricount (A, check) ;           % triangle count
-L = GrB.laplacian (A, type, check) ;    % Laplacian graph
-C = GrB.incidence (A, ...) ;            % incidence matrix
-[v, parent] = GrB.bfs (A, s, ...) ;     % breadth-first search
-iset = GrB.mis (A, check) ;             % maximal independent set
-Y = GrB.dnn (W, bias, Y0) ;             % deep neural network
-
More graph algorithms will be added in the future.
-

Thanks for watching!

Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis See also sparse, doc sparse, and https://twitter.com/DocSparse

\ No newline at end of file diff --git a/GraphBLAS/demo/html/DGX_Station/v320/graphblas_demo.html b/GraphBLAS/demo/html/DGX_Station/v320/graphblas_demo.html deleted file mode 100644 index 9cdbbacf3c..0000000000 --- a/GraphBLAS/demo/html/DGX_Station/v320/graphblas_demo.html +++ /dev/null @@ -1,2693 +0,0 @@ - - - - - GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS is a library for creating graph algorithms based on sparse linear algebraic operations over semirings. Visit http://graphblas.org for more details and resources. See also the SuiteSparse:GraphBLAS User Guide in this package.

SuiteSparse:GraphBLAS, (c) 2017-2020, Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis

Contents

GraphBLAS: faster and more general sparse matrices for MATLAB

GraphBLAS is not only useful for creating graph algorithms; it also supports a wide range of sparse matrix data types and operations. MATLAB can compute C=A*B with just two semirings: 'plus.times.double' and 'plus.times.complex' for complex matrices. GraphBLAS has 1,040 unique built-in semirings, such as 'max.plus' (https://en.wikipedia.org/wiki/Tropical_semiring). These semirings can be used to construct a wide variety of graph algorithms, based on operations on sparse adjacency matrices.

GraphBLAS supports sparse double and single precision matrices, logical, and sparse integer matrices: int8, int16, int32, int64, uint8, uint16, uint32, and uint64. Complex matrices will be added in the future.

clear all
-format compact
-rng ('default') ;
-X = 100 * rand (2) ;
-G = GrB (X)              % GraphBLAS copy of a matrix X, same type
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    81.4724
-    (2,1)    90.5792
-    (1,2)    12.6987
-    (2,2)    91.3376
-
-

Sparse integer matrices

Here's an int8 version of the same matrix:

S = int8 (G)            % convert G to a full MATLAB int8 matrix
-G = GrB (X, 'int8')      % a GraphBLAS sparse int8 matrix
-
S =
-  2×2 int8 matrix
-   81   12
-   90   91
-
-G =
-
-  2x2 GraphBLAS int8_t matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)   81
-    (2,1)   90
-    (1,2)   12
-    (2,2)   91
-
-

Sparse single-precision matrices

Matrix operations in GraphBLAS are typically as fast, or faster than MATLAB. Here's an unfair comparison: computing X^2 with MATLAB in double precision and with GraphBLAS in single precision. You would naturally expect GraphBLAS to be faster.

Please wait ...

n = 1e5 ;
-X = spdiags (rand (n, 201), -100:100, n, n) ;
-G = GrB (X, 'single') ;
-tic
-G2 = G^2 ;
-gb_time = toc ;
-tic
-X2 = X^2 ;
-matlab_time = toc ;
-fprintf ('\nGraphBLAS time: %g sec (in single)\n', gb_time) ;
-fprintf ('MATLAB time:    %g sec (in double)\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
-GraphBLAS time: 0.779341 sec (in single)
-MATLAB time:    9.53978 sec (in double)
-Speedup of GraphBLAS over MATLAB: 12.2408
-

Mixing MATLAB and GraphBLAS matrices

The error in the last computation is about eps('single') since GraphBLAS did its computation in single precision, while MATLAB used double precision. MATLAB and GraphBLAS matrices can be easily combined, as in X2-G2. The sparse single precision matrices take less memory space.

err = norm (X2 - G2, 1) / norm (X2,1)
-eps ('single')
-whos G G2 X X2
-
err =
-   1.5049e-07
-ans =
-  single
-  1.1921e-07
-  Name           Size                    Bytes  Class     Attributes
-
-  G         100000x100000            241879772  GrB                 
-  G2        100000x100000            481518572  GrB                 
-  X         100000x100000            322238408  double    sparse    
-  X2        100000x100000            641756808  double    sparse    
-
-

Faster matrix operations

But even with standard double precision sparse matrices, GraphBLAS is typically faster than the built-in MATLAB methods. Here's a fair comparison:

G = GrB (X) ;
-tic
-G2 = G^2 ;
-gb_time = toc ;
-err = norm (X2 - G2, 1) / norm (X2,1)
-fprintf ('\nGraphBLAS time: %g sec (in double)\n', gb_time) ;
-fprintf ('MATLAB time:    %g sec (in double)\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
err =
-     0
-
-GraphBLAS time: 0.929388 sec (in double)
-MATLAB time:    9.53978 sec (in double)
-Speedup of GraphBLAS over MATLAB: 10.2646
-

A wide range of semirings

MATLAB can only compute C=A*B using the standard '+.*.double' and '+.*.complex' semirings. A semiring is defined in terms of a string, 'add.mult.type', where 'add' is a monoid that takes the place of the additive operator, 'mult' is the multiplicative operator, and 'type' is the data type for the two inputs to the mult operator (the type defaults to the type of A for C=A*B).

In the standard semiring, C=A*B is defined as:

C(i,j) = sum (A(i,:).' .* B(:,j))
-

using 'plus' as the monoid and 'times' as the multiplicative operator. But in a more general semiring, 'sum' can be any monoid, which is an associative and commutative operator that has an identity value. For example, in the 'max.plus' tropical algebra, C(i,j) for C=A*B is defined as:

C(i,j) = max (A(i,:).' + B(:,j))
-

This can be computed in GraphBLAS with:

C = GrB.mxm ('max.+', A, B)
-
n = 3 ;
-A = rand (n) ;
-B = rand (n) ;
-C = zeros (n) ;
-for i = 1:n
-    for j = 1:n
-        C(i,j) = max (A (i,:).' + B (:,j)) ;
-    end
-end
-C2 = GrB.mxm ('max.+', A, B) ;
-fprintf ('\nerr = norm (C-C2,1) = %g\n', norm (C-C2,1)) ;
-
-err = norm (C-C2,1) = 0
-

The max.plus tropical semiring

Here are details of the "max.plus" tropical semiring. The identity value is -inf since max(x,-inf) = max (-inf,x) = -inf for any x.

GrB.semiringinfo ('max.+.double') ;
-
-    GraphBLAS Semiring: max.+.double (built-in)
-    GraphBLAS Monoid: semiring->add (built-in)
-    GraphBLAS BinaryOp: monoid->op (built-in) z=max(x,y)
-    GraphBLAS type: ztype double size: 8
-    GraphBLAS type: xtype double size: 8
-    GraphBLAS type: ytype double size: 8
-    identity: [    -inf ] terminal: [    inf ]
-
-    GraphBLAS BinaryOp: semiring->multiply (built-in) z=plus(x,y)
-    GraphBLAS type: ztype double size: 8
-    GraphBLAS type: xtype double size: 8
-    GraphBLAS type: ytype double size: 8
-

A boolean semiring

MATLAB cannot multiply two logical matrices. MATLAB R2019a converts them to double and uses the conventional +.*.double semiring instead. In GraphBLAS, this is the common Boolean 'or.and.logical' semiring, which is widely used in linear algebraic graph algorithms.

GrB.semiringinfo ('|.&.logical') ;
-
-    GraphBLAS Semiring: |.&.logical (built-in)
-    GraphBLAS Monoid: semiring->add (built-in)
-    GraphBLAS BinaryOp: monoid->op (built-in) z=or(x,y)
-    GraphBLAS type: ztype bool size: 1
-    GraphBLAS type: xtype bool size: 1
-    GraphBLAS type: ytype bool size: 1
-    identity: [   0 ] terminal: [   1 ]
-
-    GraphBLAS BinaryOp: semiring->multiply (built-in) z=and(x,y)
-    GraphBLAS type: ztype bool size: 1
-    GraphBLAS type: xtype bool size: 1
-    GraphBLAS type: ytype bool size: 1
-
clear
-A = sparse (rand (3) > 0.5)
-B = sparse (rand (3) > 0.2)
-
A =
-  3×3 sparse logical array
-   (2,1)      1
-   (2,2)      1
-   (3,2)      1
-   (1,3)      1
-B =
-  3×3 sparse logical array
-   (1,1)      1
-   (2,1)      1
-   (3,1)      1
-   (1,2)      1
-   (2,2)      1
-   (3,2)      1
-   (1,3)      1
-   (2,3)      1
-   (3,3)      1
-
try
-    % MATLAB R2019a does this by casting A and B to double
-    C1 = A*B
-catch
-    % MATLAB R2018a throws an error
-    fprintf ('MATLAB R2019a required for C=A*B with logical\n') ;
-    fprintf ('matrices.  Explicitly converting to double:\n') ;
-    C1 = double (A) * double (B)
-end
-C2 = GrB (A) * GrB (B)
-
MATLAB R2019a required for C=A*B with logical
-matrices.  Explicitly converting to double:
-C1 =
-   (1,1)        1
-   (2,1)        2
-   (3,1)        1
-   (1,2)        1
-   (2,2)        2
-   (3,2)        1
-   (1,3)        1
-   (2,3)        2
-   (3,3)        1
-
-C2 =
-
-  3x3 GraphBLAS bool matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)   1
-    (2,1)   1
-    (3,1)   1
-    (1,2)   1
-    (2,2)   1
-    (3,2)   1
-    (1,3)   1
-    (2,3)   1
-    (3,3)   1
-
-

Note that C1 is a MATLAB sparse double matrix, and contains non-binary values. C2 is a GraphBLAS logical matrix.

whos
-GrB.type (C2)
-
  Name      Size            Bytes  Class      Attributes
-
-  A         3x3                68  logical    sparse    
-  B         3x3               113  logical    sparse    
-  C1        3x3               176  double     sparse    
-  C2        3x3              1079  GrB                  
-
-ans =
-    'logical'
-

GraphBLAS operators, monoids, and semirings

The C interface for SuiteSparse:GraphBLAS allows for arbitrary types and operators to be constructed. However, the MATLAB interface to SuiteSparse:GraphBLAS is restricted to pre-defined types and operators: a mere 11 types, 66 unary operators, 275 binary operators, 44 monoids, 16 select operators, and 1,865 semirings (1,040 of which are unique, since some binary operators are equivalent: 'min.logical' and '&.logical' are the same thing, for example). The complex type and its binary operators, monoids, and semirings will be added in the near future.

That gives you a lot of tools to create all kinds of interesting graph algorithms. For example:

GrB.bfs    % breadth-first search
-GrB.dnn    % sparse deep neural network (http://graphchallenge.org)
-GrB.mis    % maximal independent set
-

See 'help GrB.binopinfo' for a list of the binary operators, and 'help GrB.monoidinfo' for the ones that can be used as the additive monoid in a semiring.

help GrB.binopinfo
-
 GRB.BINOPINFO list the details of a GraphBLAS binary operator.
- 
-  Usage
- 
-    GrB.binopinfo
-    GrB.binopinfo (op)
-    GrB.binopinfo (op, type)
- 
-  For GrB.binopinfo(op), the op must be a string of the form
-  'op.type', where 'op' is listed below.  The second usage allows the
-  type to be omitted from the first argument, as just 'op'.  This is
-  valid for all GraphBLAS operations, since the type defaults to the
-  type of the input matrices.  However, GrB.binopinfo does not have a
-  default type and thus one must be provided, either in the op as
-  GrB.binopinfo ('+.double'), or in the second argument, GrB.binopinfo
-  ('+', 'double').
- 
-  The MATLAB interface to GraphBLAS provides for 25 different binary
-  operators, each of which may be used with any of the 11 types, for
-  a total of 27*11 = 297 valid binary operators.  Binary operators
-  are defined by a string of the form 'op.type', or just 'op'.  In
-  the latter case, the type defaults to the type of the matrix inputs
-  to the GraphBLAS operation.
- 
-  The 6 comparator operators come in two flavors.  For the is*
-  operators, the result has the same type as the inputs, x and y,
-  with 1 for true and 0 for false.  For example isgt.double (pi, 3.0)
-  is the double value 1.0.  For the second set of 6 operators (eq,
-  ne, gt, lt, ge, le), the result is always logical (true or false).
-  In a semiring, the type of the add monoid must exactly match the
-  type of the output of the multiply operator, and thus
-  'plus.iseq.double' is valid (counting how many terms are equal).
-  The 'plus.eq.double' semiring is valid, but not the same semiring
-  since the 'plus' of 'plus.eq.double' has a logical type and is thus
-  equivalent to 'or.eq.double'.   The 'or.eq' is true if any terms
-  are equal and false otherwise (it does not count the number of
-  terms that are equal).
- 
-  The following binary operators are available.  Many have equivalent
-  synonyms, so that '1st' and 'first' both define the first(x,y) = x
-  operator.
- 
-    operator name(s) f(x,y)         |   operator names(s) f(x,y)
-    ---------------- ------         |   ----------------- ------
-    1st first        x              |   iseq             x == y
-    2nd second       y              |   isne             x ~= y
-    min              min(x,y)       |   isgt             x > y
-    max              max(x,y)       |   islt             x < y
-    +   plus         x+y            |   isge             x >= y
-    -   minus        x-y            |   isle             x <= y
-    rminus           y-x            |   ==  eq           x == y
-    *   times        x*y            |   ~=  ne           x ~= y
-    /   div          x/y            |   >   gt           x > y
-    \   rdiv         y/x            |   <   lt           x < y
-    |   || or  lor   x | y          |   >=  ge           x >= y
-    &   && and land  x & y          |   <=  le           x <= y
-    xor lxor         xor(x,y)       |
-    pair             1              |   any              x, or y
- 
-  The three logical operators, lor, land, and lxor, also come in 11
-  types.  z = lor.double (x,y) tests the condition (x~=0) || (y~=0),
-  and returns the double value 1.0 if true, or 0.0 if false.
- 
-  Example:
- 
-    % valid binary operators
-    GrB.binopinfo ('+.double') ;
-    GrB.binopinfo ('1st.int32') ;
- 
-    % invalid binary operator (an error; this is a unary op):
-    GrB.binopinfo ('abs.double') ;
- 
-  See also GrB.descriptorinfo, GrB.monoidinfo, GrB.selectopinfo,
-  GrB.semiringinfo, GrB.unopinfo.
-
-
help GrB.monoidinfo
-
 GRB.MONOIDINFO list the details of a GraphBLAS monoid.
- 
-  Usage
- 
-    GrB.monoidinfo
-    GrB.monoidinfo (monoid)
-    GrB.monoidinfo (monoid, type)
- 
-  For GrB.monoidinfo(op), the op must be a string of the form
-  'op.type', where 'op' is listed below.  The second usage allows the
-  type to be omitted from the first argument, as just 'op'.  This is
-  valid for all GraphBLAS operations, since the type defaults to the
-  type of the input matrices.  However, GrB.monoidinfo does not have a
-  default type and thus one must be provided, either in the op as
-  GrB.monoidinfo ('+.double'), or in the second argument,
-  GrB.monoidinfo ('+', 'double').
- 
-  The MATLAB interface to GraphBLAS provides for 44 different
-  monoids.  The valid monoids are: '+', '*', 'max', and 'min' for all
-  but the 'logical' type, and '|', '&', 'xor', and 'eq' for the
-  'logical' type.
- 
-  Example:
- 
-    % valid monoids
-    GrB.monoidinfo ('+.double') ;
-    GrB.monoidinfo ('*.int32') ;
- 
-    % invalid monoids
-    GrB.monoidinfo ('1st.int32') ;
-    GrB.monoidinfo ('abs.double') ;
- 
-  See also GrB.binopinfo, GrB.descriptorinfo, % GrB.selectopinfo,
-  GrB.semiringinfo, GrB.unopinfo.
-
-

Element-wise operations

Binary operators can be used in element-wise matrix operations, like C=A+B and C=A.*B. For the matrix addition C=A+B, the pattern of C is the set union of A and B, and the '+' operator is applied for entries in the intersection. Entries in A but not B, or in B but not A, are assigned to C without using the operator. The '+' operator is used for C=A+B but any operator can be used with GrB.eadd.

A = GrB (sprand (3, 3, 0.5)) ;
-B = GrB (sprand (3, 3, 0.5)) ;
-C1 = A + B
-C2 = GrB.eadd ('+', A, B)
-err = norm (C1-C2,1)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    1.47841
-    (2,2)    0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    1.47841
-    (2,2)    0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-err =
-     0
-

Subtracting two matrices

A-B and GrB.eadd ('-', A, B) are not the same thing, since the '-' operator is not applied to an entry that is in B but not A.

C1 = A-B
-C2 = GrB.eadd ('-', A, B)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    -0.666139
-    (3,1)    -0.735859
-    (1,2)    -0.334348
-    (2,2)    -0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    -0.334348
-    (2,2)    0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-

But these give the same result

C1 = A-B
-C2 = GrB.eadd ('+', A, GrB.apply ('-', B))
-err = norm (C1-C2,1)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    -0.666139
-    (3,1)    -0.735859
-    (1,2)    -0.334348
-    (2,2)    -0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    -0.666139
-    (3,1)    -0.735859
-    (1,2)    -0.334348
-    (2,2)    -0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-err =
-     0
-

Element-wise 'multiplication'

For C = A.*B, the result C is the set intersection of the pattern of A and B. The operator is applied to entries in both A and B. Entries in A but not B, or B but not A, do not appear in the result C.

C1 = A.*B
-C2 = GrB.emult ('*', A, B)
-C3 = double (A) .* double (B)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  1 nonzero, 1 entry
-
-    (1,2)    0.518474
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  1 nonzero, 1 entry
-
-    (1,2)    0.518474
-
-C3 =
-   (1,2)       0.5185
-

Just as in GrB.eadd, any operator can be used in GrB.emult:

A
-B
-C2 = GrB.emult ('max', A, B)
-
-A =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,2)    0.572029
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-B =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    0.906378
-    (2,2)    0.146938
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  1 nonzero, 1 entry
-
-    (1,2)    0.906378
-
-

Overloaded operators

The following operators all work as you would expect for any matrix. The matrices A and B can be GraphBLAS matrices, or MATLAB sparse or dense matrices, in any combination, or scalars where appropriate:

  A+B   A-B  A*B   A.*B  A./B  A.\B  A.^b   A/b   C=A(I,J)
-  -A    +A   ~A    A'    A.'   A&B   A|B    b\A   C(I,J)=A
-  A~=B  A>B  A==B  A<=B  A>=B  A<B   [A,B]  [A;B]
-  A(1:end,1:end)

For A^b, b must be a non-negative integer.

C1 = [A B] ;
-C2 = [double(A) double(B)] ;
-assert (isequal (double (C1), C2))
-
C1 = A^2
-C2 = double (A)^2 ;
-err = norm (C1 - C2, 1)
-assert (err < 1e-12)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  5 nonzeros, 5 entries
-
-    (2,2)    0.140946
-    (3,2)    0.0590838
-    (1,3)    0.142227
-    (2,3)    0.0259144
-    (3,3)    0.151809
-
-err =
-     0
-
C1 = A (1:2,2:end)
-A = double (A) ;
-C2 = A (1:2,2:end) ;
-assert (isequal (double (C1), C2))
-
-C1 =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  2 nonzeros, 2 entries
-
-    (1,1)    0.572029
-    (2,2)    0.248635
-
-

Overloaded functions

Many MATLAB built-in functions can be used with GraphBLAS matrices:

A few differences with the built-in functions:

S = sparse (G)        % makes a copy of a GrB matrix
-F = full (G)          % adds explicit zeros, so numel(F)==nnz(F)
-F = full (G,type,id)  % adds explicit identity values to a GrB matrix
-disp (G, level)       % display a GrB matrix G; level=2 is the default.
-

In the list below, the first set of Methods are overloaded built-in methods. They are used as-is on GraphBLAS matrices, such as C=abs(G). The Static methods are prefixed with "GrB.", as in C = GrB.apply ( ... ).

methods GrB
-
-Methods for class GrB:
-
-GrB             ge              le              sparse          
-abs             graph           length          spfun           
-all             gt              logical         spones          
-amd             horzcat         lt              sprand          
-and             int16           max             sprandn         
-any             int32           min             sprandsym       
-assert          int64           minus           sprintf         
-bandwidth       int8            mldivide        sqrt            
-ceil            isa             mpower          subsasgn        
-colamd          isbanded        mrdivide        subsref         
-complex         isdiag          mtimes          sum             
-conj            isempty         ne              symamd          
-ctranspose      isequal         nnz             symrcm          
-diag            isfinite        nonzeros        times           
-digraph         isfloat         norm            transpose       
-disp            ishermitian     not             tril            
-display         isinf           numel           triu            
-dmperm          isinteger       nzmax           true            
-double          islogical       ones            uint16          
-eig             ismatrix        or              uint32          
-end             isnan           plus            uint64          
-eps             isnumeric       power           uint8           
-eq              isreal          prod            uminus          
-etree           isscalar        rdivide         uplus           
-false           issparse        real            vertcat         
-find            issymmetric     repmat          xor             
-fix             istril          reshape         zeros           
-flip            istriu          round           
-floor           isvector        sign            
-fprintf         kron            single          
-full            ldivide         size            
-
-Static methods:
-
-apply           emult           issigned        reduce          
-assign          entries         kronecker       select          
-bfs             expand          ktruss          selectopinfo    
-binopinfo       extract         laplacian       semiringinfo    
-build           extracttuples   mis             speye           
-burble          eye             monoidinfo      subassign       
-chunk           finalize        mxm             threads         
-clear           format          nonz            trans           
-compact         incidence       normdiff        tricount        
-descriptorinfo  init            offdiag         type            
-dnn             isbycol         pagerank        unopinfo        
-eadd            isbyrow         prune           vreduce         
-empty           isfull          random          
-
-

Zeros are handled differently

Explicit zeros cannot be automatically dropped from a GraphBLAS matrix, like they are in MATLAB sparse matrices. In a shortest-path problem, for example, an edge A(i,j) that is missing has an infinite weight, (the monoid identity of min(x,y) is +inf). A zero edge weight A(i,j)=0 is very different from an entry that is not present in A. However, if a GraphBLAS matrix is converted into a MATLAB sparse matrix, explicit zeros are dropped, which is the convention for a MATLAB sparse matrix. They can also be dropped from a GraphBLAS matrix using the GrB.select method.

G = GrB (magic (2)) ;
-G (1,1) = 0      % G(1,1) still appears as an explicit entry
-A = double (G)   % but it's dropped when converted to MATLAB sparse
-H = GrB.select ('nonzero', G)  % drops the explicit zeros from G
-fprintf ('nnz (G): %d  nnz (A): %g nnz (H): %g\n', ...
-    nnz (G), nnz (A), nnz (H)) ;
-fprintf ('num entries in G: %d\n', GrB.entries (G)) ;
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  3 nonzeros, 4 entries
-
-    (1,1)    0
-    (2,1)    4
-    (1,2)    3
-    (2,2)    2
-
-A =
-   (2,1)        4
-   (1,2)        3
-   (2,2)        2
-
-H =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  3 nonzeros, 3 entries
-
-    (2,1)    4
-    (1,2)    3
-    (2,2)    2
-
-nnz (G): 3  nnz (A): 3 nnz (H): 3
-num entries in G: 4
-

Displaying contents of a GraphBLAS matrix

Unlike MATLAB, the default is to display just a few entries of a GrB matrix. Here are all 100 entries of a 10-by-10 matrix, using a non-default disp(G,3):

G = GrB (rand (10)) ;
-% display everything:
-disp (G,3)
-
-G =
-
-  10x10 GraphBLAS double matrix, sparse by col:
-  100 nonzeros, 100 entries
-
-    (1,1)    0.0342763
-    (2,1)    0.17802
-    (3,1)    0.887592
-    (4,1)    0.889828
-    (5,1)    0.769149
-    (6,1)    0.00497062
-    (7,1)    0.735693
-    (8,1)    0.488349
-    (9,1)    0.332817
-    (10,1)    0.0273313
-    (1,2)    0.467212
-    (2,2)    0.796714
-    (3,2)    0.849463
-    (4,2)    0.965361
-    (5,2)    0.902248
-    (6,2)    0.0363252
-    (7,2)    0.708068
-    (8,2)    0.322919
-    (9,2)    0.700716
-    (10,2)    0.472957
-    (1,3)    0.204363
-    (2,3)    0.00931977
-    (3,3)    0.565881
-    (4,3)    0.183435
-    (5,3)    0.00843818
-    (6,3)    0.284938
-    (7,3)    0.706156
-    (8,3)    0.909475
-    (9,3)    0.84868
-    (10,3)    0.564605
-    (1,4)    0.075183
-    (2,4)    0.535293
-    (3,4)    0.072324
-    (4,4)    0.515373
-    (5,4)    0.926149
-    (6,4)    0.949252
-    (7,4)    0.0478888
-    (8,4)    0.523767
-    (9,4)    0.167203
-    (10,4)    0.28341
-    (1,5)    0.122669
-    (2,5)    0.441267
-    (3,5)    0.157113
-    (4,5)    0.302479
-    (5,5)    0.758486
-    (6,5)    0.910563
-    (7,5)    0.0246916
-    (8,5)    0.232421
-    (9,5)    0.38018
-    (10,5)    0.677531
-    (1,6)    0.869074
-    (2,6)    0.471459
-    (3,6)    0.624929
-    (4,6)    0.987186
-    (5,6)    0.282885
-    (6,6)    0.843833
-    (7,6)    0.869597
-    (8,6)    0.308209
-    (9,6)    0.201332
-    (10,6)    0.706603
-    (1,7)    0.563222
-    (2,7)    0.575795
-    (3,7)    0.056376
-    (4,7)    0.73412
-    (5,7)    0.608022
-    (6,7)    0.0400164
-    (7,7)    0.540801
-    (8,7)    0.023064
-    (9,7)    0.165682
-    (10,7)    0.250393
-    (1,8)    0.23865
-    (2,8)    0.232033
-    (3,8)    0.303191
-    (4,8)    0.579934
-    (5,8)    0.267751
-    (6,8)    0.916376
-    (7,8)    0.833499
-    (8,8)    0.978692
-    (9,8)    0.734445
-    (10,8)    0.102896
-    (1,9)    0.353059
-    (2,9)    0.738955
-    (3,9)    0.57539
-    (4,9)    0.751433
-    (5,9)    0.93256
-    (6,9)    0.281622
-    (7,9)    0.51302
-    (8,9)    0.24406
-    (9,9)    0.950086
-    (10,9)    0.303638
-    (1,10)    0.563593
-    (2,10)    0.705101
-    (3,10)    0.0604146
-    (4,10)    0.672065
-    (5,10)    0.359793
-    (6,10)    0.62931
-    (7,10)    0.977758
-    (8,10)    0.394328
-    (9,10)    0.765651
-    (10,10)    0.457809
-
-
-

That was disp(G,3), so every entry was printed. It's a little long, so the default is not to print everything.

With the default display (level = 2):

G
-
-G =
-
-  10x10 GraphBLAS double matrix, sparse by col:
-  100 nonzeros, 100 entries
-
-    (1,1)    0.0342763
-    (2,1)    0.17802
-    (3,1)    0.887592
-    (4,1)    0.889828
-    (5,1)    0.769149
-    (6,1)    0.00497062
-    (7,1)    0.735693
-    (8,1)    0.488349
-    (9,1)    0.332817
-    (10,1)    0.0273313
-    (1,2)    0.467212
-    (2,2)    0.796714
-    (3,2)    0.849463
-    (4,2)    0.965361
-    (5,2)    0.902248
-    (6,2)    0.0363252
-    (7,2)    0.708068
-    (8,2)    0.322919
-    (9,2)    0.700716
-    (10,2)    0.472957
-    (1,3)    0.204363
-    (2,3)    0.00931977
-    (3,3)    0.565881
-    (4,3)    0.183435
-    (5,3)    0.00843818
-    (6,3)    0.284938
-    (7,3)    0.706156
-    (8,3)    0.909475
-    (9,3)    0.84868
-    (10,3)    0.564605
-    ...
-
-

That was disp(G,2) or just display(G), which is what is printed by a MATLAB statement that doesn't have a trailing semicolon. With level = 1, disp(G,1) gives just a terse summary:

disp (G,1)
-
-G =
-
-  10x10 GraphBLAS double matrix, sparse by col:
-  100 nonzeros, 100 entries
-
-
-

Storing a matrix by row or by column

MATLAB stores its sparse matrices by column, refered to as 'standard CSC' in SuiteSparse:GraphBLAS. In the CSC (compressed sparse column) format, each column of the matrix is stored as a list of entries, with their value and row index. In the CSR (compressed sparse row) format, each row is stored as a list of values and their column indices. GraphBLAS uses both CSC and CSR, and the two formats can be intermixed arbitrarily. In its C interface, the default format is CSR. However, for better compatibility with MATLAB, this MATLAB interface for SuiteSparse:GraphBLAS uses CSC by default instead.

rng ('default') ;
-GrB.clear ;                      % clear all prior GraphBLAS settings
-fprintf ('the default format is: %s\n', GrB.format) ;
-C = sparse (rand (2))
-G = GrB (C)
-GrB.format (G)
-
the default format is: by col
-C =
-   (1,1)       0.8147
-   (2,1)       0.9058
-   (1,2)       0.1270
-   (2,2)       0.9134
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.814724
-    (2,1)    0.905792
-    (1,2)    0.126987
-    (2,2)    0.913376
-
-ans =
-    'by col'
-

Many graph algorithms work better in CSR format, with matrices stored by row. For example, it is common to use A(i,j) for the edge (i,j), and many graph algorithms need to access the out-adjacencies of nodes, which is the row A(i,;) for node i. If the CSR format is desired, GrB.format ('by row') tells GraphBLAS to create all subsequent matrices in the CSR format. Converting from a MATLAB sparse matrix (in standard CSC format) takes a little more time (requiring a transpose), but subsequent graph algorithms can be faster.

G = GrB (C, 'by row')
-fprintf ('the format of G is:    %s\n', GrB.format (G)) ;
-H = GrB (C)
-fprintf ('the format of H is:    %s\n', GrB.format (H)) ;
-err = norm (H-G,1)
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by row:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.814724
-    (1,2)    0.126987
-    (2,1)    0.905792
-    (2,2)    0.913376
-
-the format of G is:    by row
-
-H =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.814724
-    (2,1)    0.905792
-    (1,2)    0.126987
-    (2,2)    0.913376
-
-the format of H is:    by col
-err =
-     0
-

Hypersparse matrices

SuiteSparse:GraphBLAS can use two kinds of sparse matrix data structures: standard and hypersparse, for both CSC and CSR formats. In the standard CSC format used in MATLAB, an m-by-n matrix A takes O(n+nnz(A)) space. MATLAB can create huge column vectors, but not huge matrices (when n is huge).

clear all
-[c, huge] = computer ;
-C = sparse (huge, 1)    % MATLAB can create a huge-by-1 sparse column
-try
-    C = sparse (huge, huge)     % but this fails
-catch me
-    error_expected = me
-end
-
C =
-   All zero sparse: 281474976710655×1
-error_expected = 
-  MException with properties:
-
-    identifier: 'MATLAB:array:SizeLimitExceeded'
-       message: 'Requested 281474976710655x281474976710655 (2097152.0GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See <a href="matlab: helpview([docroot '/matlab/helptargets.map'], 'matlab_env_workspace_prefs')">array size limit</a> or preference panel for more information.'
-         cause: {0×1 cell}
-         stack: [4×1 struct]
-

In a GraphBLAS hypersparse matrix, an m-by-n matrix A takes only O(nnz(A)) space. The difference can be huge if nnz (A) << n.

clear
-[c, huge] = computer ;
-G = GrB (huge, 1)            % no problem for GraphBLAS
-H = GrB (huge, huge)         % this works in GraphBLAS too
-
-G =
-
-  281474976710655x1 GraphBLAS double matrix, sparse by col:
-  no nonzeros, no entries
-
-
-H =
-
-  281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
-  no nonzeros, no entries
-
-

Operations on huge hypersparse matrices are very fast; no component of the time or space complexity is Omega(n).

I = randperm (huge, 2) ;
-J = randperm (huge, 2) ;
-H (I,J) = magic (2) ;        % add 4 nonzeros to random locations in H
-H (I,I) = 10 * [1 2 ; 3 4] ; % so H^2 is not all zero
-H = H^2 ;                    % square H
-H = (H' * 2) ;               % transpose H and double the entries
-K = pi * spones (H) ;
-H = H + K                    % add pi to each entry in H
-
-H =
-
-  281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
-  8 nonzeros, 8 entries
-
-    (27455183225557,27455183225557)    4403.14
-    (78390279669562,27455183225557)    383.142
-    (153933462881710,27455183225557)    343.142
-    (177993304104065,27455183225557)    3003.14
-    (27455183225557,177993304104065)    2003.14
-    (78390279669562,177993304104065)    183.142
-    (153933462881710,177993304104065)    143.142
-    (177993304104065,177993304104065)    1403.14
-
-

numel uses vpa if the matrix is really huge

e1 = numel (G)               % this is huge, but still a flint
-e2 = numel (H)               % this is huge^2, which needs vpa
-whos e1 e2
-
e1 =
-   2.8147e+14
-e2 =
-79228162514263774643590529025.0
-  Name      Size            Bytes  Class     Attributes
-
-  e1        1x1                 8  double              
-  e2        1x1                 8  sym                 
-
-

All of these matrices take very little memory space:

whos C G H K
-
  Name                    Size                         Bytes  Class    Attributes
-
-  G         281474976710655x1                            989  GrB                
-  H         281474976710655x281474976710655             1308  GrB                
-  K         281474976710655x281474976710655             1308  GrB                
-
-

The mask and accumulator

When not used in overloaded operators or built-in functions, many GraphBLAS methods of the form GrB.method ( ... ) can optionally use a mask and/or an accumulator operator. If the accumulator is '+' in GrB.mxm, for example, then C = C + A*B is computed. The mask acts much like logical indexing in MATLAB. With a logical mask matrix M, C<M>=A*B allows only part of C to be assigned. If M(i,j) is true, then C(i,j) can be modified. If false, then C(i,j) is not modified.

For example, to set all values in C that are greater than 0.5 to 3:

A = rand (3)
-C = GrB.assign (A, A > 0.5, 3) ;     % in GraphBLAS
-C1 = GrB (A) ; C1 (A > .5) = 3       % also in GraphBLAS
-C2 = A      ; C2 (A > .5) = 3       % in MATLAB
-err = norm (C - C1, 1)
-err = norm (C - C2, 1)
-
A =
-    0.9575    0.9706    0.8003
-    0.9649    0.9572    0.1419
-    0.1576    0.4854    0.4218
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)    3
-    (2,1)    3
-    (3,1)    0.157613
-    (1,2)    3
-    (2,2)    3
-    (3,2)    0.485376
-    (1,3)    3
-    (2,3)    0.141886
-    (3,3)    0.421761
-
-C2 =
-    3.0000    3.0000    3.0000
-    3.0000    3.0000    0.1419
-    0.1576    0.4854    0.4218
-err =
-     0
-err =
-     0
-

The descriptor

Most GraphBLAS functions of the form GrB.method ( ... ) take an optional last argument, called the descriptor. It is a MATLAB struct that can modify the computations performed by the method. 'help GrB.descriptorinfo' gives all the details. The following is a short summary of the primary settings:

d.out = 'default' or 'replace', clears C after the accum op is used.

d.mask = 'default' or 'complement', to use M or ~M as the mask matrix; 'structural', or 'structural complement', to use the pattern of M or ~M.

d.in0 = 'default' or 'transpose', to transpose A for C=A*B, C=A+B, etc.

d.in1 = 'default' or 'transpose', to transpose B for C=A*B, C=A+B, etc.

d.kind = 'default', 'GrB', 'sparse', or 'full'; the output of GrB.method.

A = sparse (rand (2)) ;
-B = sparse (rand (2)) ;
-C1 = A'*B ;
-C2 = GrB.mxm ('+.*', A, B, struct ('in0', 'transpose')) ;
-err = norm (C1-C2,1)
-
err =
-     0
-

Integer arithmetic is different in GraphBLAS

MATLAB supports integer arithmetic on its full matrices, using int8, int16, int32, int64, uint8, uint16, uint32, or uint64 data types. None of these integer data types can be used to construct a MATLAB sparse matrix, which can only be double, double complex, or logical. Furthermore, C=A*B is not defined for integer types in MATLAB, except when A and/or B are scalars.

GraphBLAS supports all of those types for its sparse matrices (except for complex, which will be added in the future). All operations are supported, including C=A*B when A or B are any integer type, for all 1,865 semirings (1,040 of which are unique).

However, integer arithmetic differs in GraphBLAS and MATLAB. In MATLAB, integer values saturate if they exceed their maximum value. In GraphBLAS, integer operators act in a modular fashion. The latter is essential when computing C=A*B over a semiring. A saturating integer operator cannot be used as a monoid since it is not associative.

The C API for GraphBLAS allows for the creation of arbitrary user-defined types, so it would be possible to create different binary operators to allow element-wise integer operations to saturate, perhaps:

C = GrB.eadd('+saturate',A,B)
-

This would require an extension to this MATLAB interface.

C = uint8 (magic (3)) ;
-G = GrB (C) ;
-C1 = C * 40
-C2 = G * 40
-C3 = double (G) * 40 ;
-S = double (C1 < 255) ;
-assert (isequal (double (C1).*S, double (C2).*S))
-assert (isequal (nonzeros (C2), double (mod (nonzeros (C3), 256))))
-
C1 =
-  3×3 uint8 matrix
-   255    40   240
-   120   200   255
-   160   255    80
-
-C2 =
-
-  3x3 GraphBLAS uint8_t matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)   64
-    (2,1)   120
-    (3,1)   160
-    (1,2)   40
-    (2,2)   200
-    (3,2)   104
-    (1,3)   240
-    (2,3)   24
-    (3,3)   80
-
-

An example graph algorithm: breadth-first search

The breadth-first search of a graph finds all nodes reachable from the source node, and their level, v. v=GrB.bfs(A,s) or v=bfs_matlab(A,s) compute the same thing, but GrB.bfs uses GraphBLAS matrices and operations, while bfs_matlab uses pure MATLAB operations. v is defined as v(s) = 1 for the source node, v(i) = 2 for nodes adjacent to the source, and so on.

clear all
-rng ('default') ;
-n = 1e5 ;
-A = logical (sprandn (n, n, 1e-3)) ;
-
-tic
-v1 = GrB.bfs (A, 1) ;
-gb_time = toc ;
-
-tic
-v2 = bfs_matlab (A, 1) ;
-matlab_time = toc ;
-
-assert (isequal (double (v1'), v2))
-fprintf ('\nnodes reached: %d of %d\n', nnz (v2), n) ;
-fprintf ('GraphBLAS time: %g sec\n', gb_time) ;
-fprintf ('MATLAB time:    %g sec\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
-nodes reached: 100000 of 100000
-GraphBLAS time: 0.315912 sec
-MATLAB time:    1.10726 sec
-Speedup of GraphBLAS over MATLAB: 3.50496
-

Example graph algorithm: Luby's method in GraphBLAS

The GrB.mis.m function is variant of Luby's randomized algorithm [Luby 1985]. It is a parallel method for finding an maximal independent set of nodes, where no two nodes are adjacent. See the GraphBLAS/@GrB/GrB.mis.m function for details. The graph must be symmetric with a zero-free diagonal, so A is symmetrized first and any diagonal entries are removed.

A = GrB (A) ;
-A = GrB.offdiag (A|A') ;
-
-tic
-s = GrB.mis (A) ;
-toc
-fprintf ('# nodes in the graph: %g\n', size (A,1)) ;
-fprintf ('# edges: : %g\n', GrB.entries (A) / 2) ;
-fprintf ('size of maximal independent set found: %g\n', ...
-    full (double (sum (s)))) ;
-
-% make sure it's independent
-p = find (s) ;
-S = A (p,p) ;
-assert (GrB.entries (S) == 0)
-
-% make sure it's maximal
-notp = find (s == 0) ;
-S = A (notp, p) ;
-deg = GrB.vreduce ('+.int64', S) ;
-assert (logical (all (deg > 0)))
-
Elapsed time is 0.393703 seconds.
-# nodes in the graph: 100000
-# edges: : 9.9899e+06
-size of maximal independent set found: 2811
-

Sparse deep neural network

The 2019 MIT GraphChallenge (see http://graphchallenge.org) is to solve a set of large sparse deep neural network problems. In this demo, the MATLAB reference solution is compared with a solution using GraphBLAS, for a randomly constructed neural network. See the GrB.dnn and dnn_matlab.m functions for details.

clear all
-rng ('default') ;
-nlayers = 16 ;
-nneurons = 4096 ;
-nfeatures = 30000 ;
-fprintf ('# layers:   %d\n', nlayers) ;
-fprintf ('# neurons:  %d\n', nneurons) ;
-fprintf ('# features: %d\n', nfeatures) ;
-
-tic
-Y0 = sprand (nfeatures, nneurons, 0.1) ;
-for layer = 1:nlayers
-    W {layer} = sprand (nneurons, nneurons, 0.01) * 0.2 ;
-    bias {layer} = -0.2 * ones (1, nneurons) ;
-end
-t_setup = toc ;
-fprintf ('construct problem time: %g sec\n', t_setup) ;
-
-% convert the problem from MATLAB to GraphBLAS
-t = tic ;
-[W_gb, bias_gb, Y0_gb] = dnn_mat2gb (W, bias, Y0) ;
-t = toc (t) ;
-fprintf ('setup time: %g sec\n', t) ;
-
# layers:   16
-# neurons:  4096
-# features: 30000
-construct problem time: 7.8016 sec
-setup time: 0.156962 sec
-

Solving the sparse deep neural network problem with GraphbLAS

Please wait ...

tic
-Y1 = GrB.dnn (W_gb, bias_gb, Y0_gb) ;
-gb_time = toc ;
-fprintf ('total time in GraphBLAS: %g sec\n', gb_time) ;
-
total time in GraphBLAS: 3.42888 sec
-

Solving the sparse deep neural network problem with MATLAB

Please wait ...

tic
-Y2 = dnn_matlab (W, bias, Y0) ;
-matlab_time = toc ;
-fprintf ('total time in MATLAB:    %g sec\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
-err = norm (Y1-Y2,1)
-
total time in MATLAB:    128.26 sec
-Speedup of GraphBLAS over MATLAB: 37.4059
-err =
-     0
-

For objects, GraphBLAS has better colon notation than MATLAB

The MATLAB notation C = A (start:inc:fini) is very handy, and it works great if A is a MATLAB matrix. But for objects like the GraphBLAS matrix, MATLAB starts by creating the explicit index vector I = start:inc:fini. That's fine if the matrix is modest in size, but GraphBLAS can construct huge matrices. The problem is that 1:n cannot be explicitly constructed when n is huge.

The C API for GraphBLAS can represent the colon notation start:inc:fini in an implicit manner, so it can do the indexing without actually forming the explicit list I = start:inc:fini. But there is no access to this method using the MATLAB notation start:inc:fini.

Thus, to compute C = A (start:inc:fini) for very huge matrices, you need to use use a cell array to represent the colon notation, as { start, inc, fini }, instead of start:inc:fini. See 'help GrB.extract' and 'help.gbsubassign' for, for C(I,J)=A. The syntax isn't conventional, but it is far faster than the MATLAB colon notation for objects, and takes far less memory when I is huge.

n = 1e14 ;
-H = GrB (n, n) ;            % a huge empty matrix
-I = [1 1e9 1e12 1e14] ;
-M = magic (4)
-H (I,I) = M ;
-J = {1, 1e13} ;            % represents 1:1e13 colon notation
-C1 = H (J, J)              % computes C1 = H (1:e13,1:1e13)
-c = nonzeros (C1) ;
-m = nonzeros (M (1:3, 1:3)) ;
-assert (isequal (c, m)) ;
-
M =
-    16     2     3    13
-     5    11    10     8
-     9     7     6    12
-     4    14    15     1
-
-C1 =
-
-  10000000000000x10000000000000 GraphBLAS double matrix, hypersparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)    16
-    (1000000000,1)    5
-    (1000000000000,1)    9
-    (1,1000000000)    2
-    (1000000000,1000000000)    11
-    (1000000000000,1000000000)    7
-    (1,1000000000000)    3
-    (1000000000,1000000000000)    10
-    (1000000000000,1000000000000)    6
-
-
try
-    % try to compute the same thing with colon
-    % notation (1:1e13), but this fails:
-    C2 = H (1:1e13, 1:1e13)
-catch me
-    error_expected = me
-end
-
error_expected = 
-  MException with properties:
-
-    identifier: 'MATLAB:array:SizeLimitExceeded'
-       message: 'Requested 10000000000000x1 (74505.8GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See <a href="matlab: helpview([docroot '/matlab/helptargets.map'], 'matlab_env_workspace_prefs')">array size limit</a> or preference panel for more information.'
-         cause: {}
-         stack: [4×1 struct]
-

Iterative solvers work as-is

Many built-in functions work with GraphBLAS matrices unmodified.

A = sparse (rand (4)) ;
-b = sparse (rand (4,1)) ;
-x = gmres (A,b)
-norm (A*x-b)
-x = gmres (GrB(A), GrB(b))
-norm (A*x-b)
-
gmres converged at iteration 4 to a solution with relative residual 0.
-x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
-ans =
-   8.6711e-16
-gmres converged at iteration 4 to a solution with relative residual 0.
-x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
-ans =
-   7.2802e-16
-

... even in single precision

x = gmres (GrB(A,'single'), GrB(b,'single'))
-norm (A*x-b)
-
gmres converged at iteration 4 to a solution with relative residual 0.
-x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
-ans =
-   3.5566e-07
-

Both of the following uses of minres (A,b) fail to converge because A is not symmetric, as the method requires. Both failures are correctly reported, and both the MATLAB version and the GraphBLAS version return the same incorrect vector x.

x = minres (A, b)
-x = minres (GrB(A), GrB(b))
-
minres stopped at iteration 4 without converging to the desired tolerance 1e-06
-because the maximum number of iterations was reached.
-The iterate returned (number 4) has relative residual 0.21.
-x =
-    0.2489
-    0.2081
-    0.0700
-    0.3928
-minres stopped at iteration 4 without converging to the desired tolerance 1e-06
-because the maximum number of iterations was reached.
-The iterate returned (number 4) has relative residual 0.21.
-
-x =
-
-  4x1 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.248942
-    (2,1)    0.208128
-    (3,1)    0.0699707
-    (4,1)    0.392812
-
-

With a proper symmetric matrix

A = A+A' ;
-x = minres (A, b)
-norm (A*x-b)
-x = minres (GrB(A), GrB(b))
-norm (A*x-b)
-
minres converged at iteration 4 to a solution with relative residual 1.3e-11.
-x =
- -114.0616
-   -1.4211
-  134.8227
-    2.0694
-ans =
-   1.3650e-11
-minres converged at iteration 4 to a solution with relative residual 1.3e-11.
-
-x =
-
-  4x1 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    -114.062
-    (2,1)    -1.4211
-    (3,1)    134.823
-    (4,1)    2.0694
-
-ans =
-   1.3650e-11
-

Extreme performance differences between GraphBLAS and MATLAB.

The GraphBLAS operations used so far are perhaps 2x to 50x faster than the corresponding MATLAB operations, depending on how many cores your computer has. To run a demo illustrating a 500x or more speedup versus MATLAB, run this demo:

  gbdemo2

It will illustrate an assignment C(I,J)=A that can take under a second in GraphBLAS but several minutes in MATLAB. To make the comparsion even more dramatic, try:

  gbdemo2 (20000)

assuming you have enough memory. The gbdemo2 is not part of this demo since it can take a long time; it tries a range of problem sizes, and each one takes several minutes in MATLAB.

Sparse logical indexing is much, much faster in GraphBLAS

The mask in GraphBLAS acts much like logical indexing in MATLAB, but it is not quite the same. MATLAB logical indexing takes the form:

     C (M) = A (M)

which computes the same thing as the GraphBLAS statement:

     C = GrB.assign (C, M, A)

The GrB.assign statement computes C(M)=A(M), and it is vastly faster than C(M)=A(M), even if the time to convert the GrB matrix back to a MATLAB sparse matrix is included.

GraphBLAS can also compute C (M) = A (M) using overloaded operators for subsref and subsasgn, but C = GrB.assign (C, M, A) is a bit faster.

First, both methods in GraphBLAS (both are very fast):

clear
-n = 4000 ;
-tic
-C = sprand (n, n, 0.1) ;
-A = 100 * sprand (n, n, 0.1) ;
-M = (C > 0.5) ;
-t_setup = toc ;
-fprintf ('nnz(C): %g, nnz(M): %g, nnz(A): %g\n', ...
-    nnz(C), nnz(M), nnz(A)) ;
-fprintf ('\nsetup time:     %g sec\n', t_setup) ;
-
-% include the time to convert C1 from a GraphBLAS
-% matrix to a MATLAB sparse matrix:
-tic
-C1 = GrB.assign (C, M, A) ;
-C1 = double (C1) ;
-gb_time = toc ;
-fprintf ('\nGraphBLAS time: %g sec for GrB.assign\n', gb_time) ;
-
-% now using overloaded operators, also include the time to
-% convert back to a MATLAB sparse matrix, for good measure:
-A2 = GrB (A) ;
-C2 = GrB (C) ;
-tic
-C2 (M) = A2 (M) ;
-C2 = double (C2) ;
-gb_time2 = toc ;
-fprintf ('\nGraphBLAS time: %g sec for C(M)=A(M)\n', gb_time2) ;
-
nnz(C): 1.5226e+06, nnz(M): 761163, nnz(A): 1.52245e+06
-
-setup time:     1.33984 sec
-
-GraphBLAS time: 0.018929 sec for GrB.assign
-
-GraphBLAS time: 0.072552 sec for C(M)=A(M)
-

Please wait, this will take about 10 minutes or so ...

tic
-C (M) = A (M) ;
-matlab_time = toc ;
-
-fprintf ('\nGraphBLAS time: %g sec (GrB.assign)\n', gb_time) ;
-fprintf ('\nGraphBLAS time: %g sec (overloading)\n', gb_time2) ;
-fprintf ('MATLAB time:    %g sec\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time2) ;
-
-% GraphBLAS computes the exact same result with both methods:
-assert (isequal (C1, C))
-assert (isequal (C2, C))
-C1 - C
-C2 - C
-
-GraphBLAS time: 0.018929 sec (GrB.assign)
-
-GraphBLAS time: 0.072552 sec (overloading)
-MATLAB time:    1113.39 sec
-Speedup of GraphBLAS over MATLAB: 15346.2
-ans =
-   All zero sparse: 4000×4000
-ans =
-   All zero sparse: 4000×4000
-

Limitations and their future solutions

The MATLAB interface for SuiteSparse:GraphBLAS is a work-in-progress. It has some limitations, most of which will be resolved over time.

(1) Nonblocking mode:

GraphBLAS has a 'non-blocking' mode, in which operations can be left pending and completed later. SuiteSparse:GraphBLAS uses the non-blocking mode to speed up a sequence of assignment operations, such as C(I,J)=A. However, in its MATLAB interface, this would require a MATLAB mexFunction to modify its inputs. That breaks the MATLAB API standard, so it cannot be safely done. As a result, using GraphBLAS via its MATLAB interface can be slower than when using its C API. This restriction would not be a limitation if GraphBLAS were to be incorporated into MATLAB itself, but there is likely no way to do this in a mexFunction interface to GraphBLAS.

(2) Complex matrices:

GraphBLAS can operate on matrices with arbitrary user-defined types and operators. The only constraint is that the type be a fixed sized typedef that can be copied with the ANSI C memcpy; variable-sized types are not yet supported. However, in this MATLAB interface, SuiteSparse:GraphBLAS has access to only predefined types, operators, and semirings. Complex types and operators will be added to this MATLAB interface in the future. They already appear in the C version of GraphBLAS, with user-defined operators in GraphBLAS/Demo/Source/usercomplex.c.

(3) Integer element-wise operations:

Integer operations in MATLAB saturate, so that uint8(255)+1 is 255. To allow for integer monoids, GraphBLAS uses modular arithmetic instead. This is the only way that C=A*B can be defined for integer semirings. However, saturating integer operators could be added in the future, so that element- wise integer operations on GraphBLAS sparse integer matrices could work just the same as their MATLAB counterparts.

So in the future, you could perhaps write this, for both sparse and dense integer matrices A and B:

     C = GrB.eadd ('+saturate.int8', A, B)

to compute the same thing as C=A+B in MATLAB for its full int8 matrices. Note that MATLAB can do this only for dense integer matrices, since it doesn't support sparse integer matrices.

(4) Faster methods:

Most methods in this MATLAB interface are based on efficient parallel C functions in GraphBLAS itself, and are typically as fast or faster than the equivalent built-in operators and functions in MATLAB.

There are few notable exceptions; these will be addressed in the future. Dense matrices and vectors held as GraphBLAS objects are slower than their MATLAB counterparts. horzcat and vertcat, for [A B] and [A;B] when either A or B are GraphBLAS matrices, are also slow, as illustrated below in the next example.

Other methods that will be faster in the future include bandwidth, istriu, istril, eps, ceil, floor, round, fix, isfinite, isinf, isnan, spfun, and A.^B. These methods are currently implemented in m-files, not in efficient parallel C functions.

Here is an example that illustrates the performance of C = [A B]

clear
-A = sparse (rand (2000)) ;
-B = sparse (rand (2000)) ;
-tic
-C1 = [A B] ;
-matlab_time = toc ;
-
-A = GrB (A) ;
-B = GrB (B) ;
-tic
-C2 = [A B] ;
-gb_time = toc ;
-
-err = norm (C1-C2,1)
-fprintf ('\nMATLAB: %g sec, GraphBLAS: %g sec\n', ...
-    matlab_time, gb_time) ;
-if (gb_time > matlab_time)
-    fprintf ('GraphBLAS is slower by a factor of %g\n', ...
-        gb_time / matlab_time) ;
-end
-
err =
-     0
-
-MATLAB: 0.066463 sec, GraphBLAS: 0.194094 sec
-GraphBLAS is slower by a factor of 2.92033
-

(5) Linear indexing:

If A is an m-by-n 2D MATLAB matrix, with n > 1, A(:) is a column vector of length m*n. The index operation A(i) accesses the ith entry in the vector A(:). This is called linear indexing in MATLAB. It is not yet available for GraphBLAS matrices in this MATLAB interface to GraphBLAS, but it could be added in the future.

(6) Implicit singleton dimension expansion

In MATLAB C=A+B where A is m-by-n and B is a 1-by-n row vector implicitly expands B to a matrix, computing C(i,j)=A(i,j)+B(j). This implicit expansion is not yet suported in GraphBLAS with C=A+B. However, it can be done with C = GrB.mxm ('+.+', A, diag(GrB(B))). That's an nice example of the power of semirings, but it's not immediately obvious, and not as clear a syntax as C=A+B. The GraphBLAS/@GrB/dnn.m function uses this 'plus.plus' semiring to apply the bias to each neuron.

A = magic (3)
-B = 1000:1000:3000
-C1 = A + B
-C2 = GrB.mxm ('+.+', A, diag (GrB (B)))
-err = norm (C1-C2,1)
-
A =
-     8     1     6
-     3     5     7
-     4     9     2
-B =
-        1000        2000        3000
-C1 =
-        1008        2001        3006
-        1003        2005        3007
-        1004        2009        3002
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)    1008
-    (2,1)    1003
-    (3,1)    1004
-    (1,2)    2001
-    (2,2)    2005
-    (3,2)    2009
-    (1,3)    3006
-    (2,3)    3007
-    (3,3)    3002
-
-err =
-     0
-

GraphBLAS operations

In addition to the overloaded operators (such as C=A*B) and overloaded functions (such as L=tril(A)), GraphBLAS also has methods of the form GrB.method, listed on the next page. Most of them take an optional input matrix Cin, which is the initial value of the matrix C for the expression below, an optional mask matrix M, and an optional accumulator operator.

    C<#M,replace> = accum (C, T)

In the above expression, #M is either empty (no mask), M (with a mask matrix) or ~M (with a complemented mask matrix), as determined by the descriptor. 'replace' can be used to clear C after it is used in accum(C,T) but before it is assigned with C<...> = Z, where Z=accum(C,T). The matrix T is the result of some operation, such as T=A*B for GrB.mxm, or T=op(A,B) for GrB.eadd.

A summary of these GrB.methods is on the next pages.

Methods for the GrB class:

These methods operate on GraphBLAS matrices only, and they overload
-the existing MATLAB functions of the same name.
-
C = GrB (...)           construct a GraphBLAS matrix
-C = sparse (G)          makes a copy of a GrB matrix
-C = full (G, ...)       adds explicit zeros or id values to a GrB matrix
-C = double (G)          cast GrB matrix to MATLAB sparse double matrix
-C = logical (G)         cast GrB matrix to MATLAB sparse logical matrix
-C = complex (G)         cast GrB matrix to MATLAB sparse complex
-C = single (G)          cast GrB matrix to MATLAB full single matrix
-C = int8 (G)            cast GrB matrix to MATLAB full int8 matrix
-C = int16 (G)           cast GrB matrix to MATLAB full int16 matrix
-C = int32 (G)           cast GrB matrix to MATLAB full int32 matrix
-C = int64 (G)           cast GrB matrix to MATLAB full int64 matrix
-C = uint8 (G)           cast GrB matrix to MATLAB full uint8 matrix
-C = uint16 (G)          cast GrB matrix to MATLAB full uint16 matrix
-C = uint32 (G)          cast GrB matrix to MATLAB full uint32 matrix
-C = uint64 (G)          cast GrB matrix to MATLAB full uint64 matrix
-C = cast (G,...)        cast GrB matrix to MATLAB matrix (as above)
-
X = nonzeros (G)        extract all entries from a GrB matrix
-[I,J,X] = find (G)      extract all entries from a GrB matrix
-C = spones (G)          return pattern of GrB matrix
-disp (G, level)         display a GrB matrix G
-display (G)             display a GrB matrix G; same as disp(G,2)
-mn = numel (G)          m*n for an m-by-n GrB matrix G
-e = nnz (G)             number of entries in a GrB matrix G
-e = nzmax (G)           number of entries in a GrB matrix G
-[m n] = size (G)        size of a GrB matrix G
-n = length (G)          length of a GrB vector
-s = isempty (G)         true if any dimension of G is zero
-s = issparse (G)        true for any GrB matrix G
-s = ismatrix (G)        true for any GrB matrix G
-s = isvector (G)        true if m=1 or n=1, for an m-by-n GrB matrix G
-s = iscolumn (G)        true if n=1, for an m-by-n GrB matrix G
-s = isrow (G)           true if m=1, for an m-by-n GrB matrix G
-s = isscalar (G)        true if G is a 1-by-1 GrB matrix
-s = isnumeric (G)       true for any GrB matrix G (even logical)
-s = isfloat (G)         true if GrB matrix is double, single, complex
-s = isreal (G)          true if GrB matrix is not complex
-s = isinteger (G)       true if GrB matrix is int8, int16, ..., uint64
-s = islogical (G)       true if GrB matrix is logical
-s = isa (G, classname)  check if a GrB matrix is of a specific class
-
C = diag (G,k)          diagonal matrices and diagonals of GrB matrix G
-L = tril (G,k)          lower triangular part of GrB matrix G
-U = triu (G,k)          upper triangular part of GrB matrix G
-C = kron (A,B)          Kronecker product
-C = repmat (G, ...)     replicate and tile a GraphBLAS matrix
-C = reshape (G, ...)    reshape a GraphBLAS matrix
-C = abs (G)             absolute value
-C = sign (G)            signum function
-s = istril (G)          true if G is lower triangular
-s = istriu (G)          true if G is upper triangular
-s = isbanded (G,...)    true if G is banded
-s = isdiag (G)          true if G is diagonal
-s = ishermitian (G)     true if G is Hermitian
-s = issymmetric (G)     true if G is symmetric
-[lo,hi] = bandwidth (G) determine the lower & upper bandwidth of G
-C = sum (G, option)     reduce via sum, to vector or scalar
-C = prod (G, option)    reduce via product, to vector or scalar
-s = norm (G, kind)      1-norm or inf-norm of a GrB matrix
-C = max (G, ...)        reduce via max, to vector or scalar
-C = min (G, ...)        reduce via min, to vector or scalar
-C = any (G, ...)        reduce via '|', to vector or scalar
-C = all (G, ...)        reduce via '&', to vector or scalar
-
C = sqrt (G)            element-wise square root
-C = eps (G)             floating-point spacing
-C = ceil (G)            round towards infinity
-C = floor (G)           round towards -infinity
-C = round (G)           round towards nearest
-C = fix (G)             round towards zero
-C = isfinite (G)        test if finite
-C = isinf (G)           test if infinite
-C = isnan (G)           test if NaN
-C = spfun (fun, G)      evaluate a function on the entries of G
-p = amd (G)             approximate minimum degree ordering
-p = colamd (G)          column approximate minimum degree ordering
-p = symamd (G)          approximate minimum degree ordering
-p = symrcm (G)          reverse Cuthill-McKee ordering
-[...] = dmperm (G)      Dulmage-Mendelsohn permutation
-parent = etree (G)      elimination tree
-C = conj (G)            complex conjugate
-C = real (G)            real part of a complex GraphBLAS matrix
-[V, ...] = eig (G,...)  eigenvalues and eigenvectors
-assert (G)              generate an error if G is false
-C = zeros (...,'like',G)   all-zero matrix, same type as G
-C = false (...,'like',G)   all-false logical matrix
-C = ones (...,'like',G)    matrix with all ones, same type as G
-

Operator overloading:

C = plus (A, B)         C = A + B
-C = minus (A, B)        C = A - B
-C = uminus (G)          C = -G
-C = uplus (G)           C = +G
-C = times (A, B)        C = A .* B
-C = mtimes (A, B)       C = A * B
-C = rdivide (A, B)      C = A ./ B
-C = ldivide (A, B)      C = A .\ B
-C = mrdivide (A, B)     C = A / B
-C = mldivide (A, B)     C = A \ B
-C = power (A, B)        C = A .^ B
-C = mpower (A, B)       C = A ^ B
-C = lt (A, B)           C = A < B
-C = gt (A, B)           C = A > B
-C = le (A, B)           C = A <= B
-C = ge (A, B)           C = A >= B
-C = ne (A, B)           C = A ~= B
-C = eq (A, B)           C = A == B
-C = and (A, B)          C = A & B
-C = or (A, B)           C = A | B
-C = not (G)             C = ~G
-C = ctranspose (G)      C = G'
-C = transpose (G)       C = G.'
-C = horzcat (A, B)      C = [A , B]
-C = vertcat (A, B)      C = [A ; B]
-C = subsref (A, I, J)   C = A (I,J) or C = A (M)
-C = subsasgn (A, I, J)  C (I,J) = A
-index = end (A, k, n)   for object indexing, A(1:end,1:end)
-

Static Methods:

The Static Methods for the GrB class can be used on input matrices of
-any kind: GraphBLAS sparse matrices, MATLAB sparse matrices, or
-MATLAB dense matrices, in any combination.  The output matrix Cout is
-a GraphBLAS matrix, by default, but can be optionally returned as a
-MATLAB sparse or dense matrix.  The static methods divide into two
-categories: those that perform basic functions, and the GraphBLAS
-operations that use the mask/accum.
-

GraphBLAS basic functions:

GrB.clear                    clear GraphBLAS workspace and settings
-GrB.descriptorinfo (d)       list properties of a descriptor
-GrB.unopinfo (op, type)      list properties of a unary operator
-GrB.binopinfo (op, type)     list properties of a binary operator
-GrB.monoidinfo (op, type)    list properties of a monoid
-GrB.semiringinfo (s, type)   list properties of a semiring
-t = GrB.threads (t)          set/get # of threads to use in GraphBLAS
-c = GrB.chunk (c)            set/get chunk size to use in GraphBLAS
-b = GrB.burble (b)           set/get burble (diagnostic output)
-result = GrB.entries (G,...) count or query entries in a matrix
-result = GrB.nonz (G,...)    count or query nonzeros in a matrix
-C = GrB.prune (A, id)        prune entries equal to id
-C = GrB.offdiag (A)          prune diagonal entries
-s = GrB.isfull (A)           true if all entries present
-[C,I,J] = GrB.compact (A,id) remove empty rows and columns
-G = GrB.empty (m, n)         return an empty GraphBLAS matrix
-s = GrB.type (A)             get the type of a MATLAB or GrB matrix A
-s = GrB.issigned (type)      true if type is signed
-f = GrB.format (f)           set/get matrix format to use in GraphBLAS
-s = GrB.isbyrow (A)          true if format f A is 'by row'
-s = GrB.isbycol (A)          true if format f A is 'by col'
-C = GrB.expand (scalar, A)   expand a scalar (C = scalar*spones(A))
-C = GrB.eye                  identity matrix of any type
-C = GrB.speye                identity matrix (of type 'double')
-C = GrB.build (I, J, X, m, n, dup, type, desc)
-                             build a GrB matrix from list of entries
-[I,J,X] = GrB.extracttuples (A, desc)
-                             extract all entries from a matrix
-s = GrB.normdiff (A, B, kind)   norm (A-B,kind)
-

GraphBLAS operations with Cout, mask M, and accum.

Cout = GrB.mxm (Cin, M, accum, semiring, A, B, desc)
-                sparse matrix-matrix multiplication over a semiring
-Cout = GrB.select (Cin, M, accum, op, A, b, desc)
-                select a subset of entries from a matrix
-Cout = GrB.assign (Cin, M, accum, A, I, J, desc)
-                sparse matrix assignment, such as C(I,J)=A
-Cout = GrB.subassign (Cin, M, accum, A, I, J, desc)
-                sparse matrix assignment, such as C(I,J)=A
-Cout = GrB.vreduce (Cin, M, accum, op, A, desc)
-                reduce a matrix to a vector
-Cout = GrB.reduce (Cin, accum, op, A, desc)
-                reduce a matrix to a scalar
-Cout = GrB.kronecker (Cin, M, accum, op, A, B, desc)
-                Kronecker product
-Cout = GrB.trans (Cin, M, accum, A, desc)
-                transpose a matrix
-Cout = GrB.eadd (Cin, M, accum, op, A, B, desc)
-                element-wise addition
-Cout = GrB.emult (Cin, M, accum, op, A, B, desc)
-                element-wise multiplication
-Cout = GrB.apply (Cin, M, accum, op, A, desc)
-                apply a unary operator
-Cout = GrB.extract (Cin, M, accum, A, I, J, desc)
-                extract submatrix, like C=A(I,J) in MATLAB
-

GraphBLAS operations (with Cout, Cin arguments) take the following form:

C<#M,replace> = accum (C, operation (A or A', B or B'))
-
C is both an input and output matrix.  In this MATLAB interface to
-GraphBLAS, it is split into Cin (the value of C on input) and Cout
-(the value of C on output).  M is the optional mask matrix, and #M is
-either M or !M depending on whether or not the mask is complemented
-via the desc.mask option.  The replace option is determined by
-desc.out; if present, C is cleared after it is used in the accum
-operation but before the final assignment.  A and/or B may optionally
-be transposed via the descriptor fields desc.in0 and desc.in1,
-respectively.  To select the format of Cout, use desc.format.  See
-GrB.descriptorinfo for more details.
-
accum is optional; if not is not present, then the operation becomes
-C<...> = operation(A,B).  Otherwise, C = C + operation(A,B) is
-computed where '+' is the accum operator.  It acts like a sparse
-matrix addition (see GrB.eadd), in terms of the structure of the
-result C, but any binary operator can be used.
-
The mask M acts like MATLAB logical indexing.  If M(i,j)=1 then
-C(i,j) can be modified; if zero, it cannot be modified by the
-operation.
-

Static Methods for graph algorithms:

r = GrB.pagerank (A, opts) ;            % PageRank of a matrix
-C = GrB.ktruss (A, k, check) ;          % k-truss
-s = GrB.tricount (A, check) ;           % triangle count
-L = GrB.laplacian (A, type, check) ;    % Laplacian graph
-C = GrB.incidence (A, ...) ;            % incidence matrix
-[v, parent] = GrB.bfs (A, s, ...) ;     % breadth-first search
-iset = GrB.mis (A, check) ;             % maximal independent set
-Y = GrB.dnn (W, bias, Y0) ;             % deep neural network
-
More graph algorithms will be added in the future.
-

Thanks for watching!

Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis See also sparse, doc sparse, and https://twitter.com/DocSparse

\ No newline at end of file diff --git a/GraphBLAS/demo/html/DellXPS13/README.txt b/GraphBLAS/demo/html/DellXPS13/README.txt index 2f0955020e..34cde5d20a 100644 --- a/GraphBLAS/demo/html/DellXPS13/README.txt +++ b/GraphBLAS/demo/html/DellXPS13/README.txt @@ -2,11 +2,7 @@ Results on a Dell XPS 13 9380 laptop. Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz (up to 4.6GHz), 16GB of RAM. MATLAB R2019a. Ubuntu 18.04. GraphBLAS and -the mexFunction interface compiled with gcc 7.4.0. The CPU +the mexFunction interface compiled with gcc 7.5.0. The CPU has 4 hardware cores, and 4 threads were used (the default when running OpenMP inside MATLAB). -v310: output from GraphBLAS v3.1.0 -v312: output from GraphBLAS v3.1.2 (draft, Nov 15, 2019) -v320: output from GraphBLAS v3.2.0 (Feb 20, 2020) - diff --git a/GraphBLAS/demo/html/DellXPS13/graphblas_demo.html b/GraphBLAS/demo/html/DellXPS13/graphblas_demo.html new file mode 100644 index 0000000000..df81ffa1e9 --- /dev/null +++ b/GraphBLAS/demo/html/DellXPS13/graphblas_demo.html @@ -0,0 +1,2407 @@ + + + + + GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS is a library for creating graph algorithms based on sparse linear algebraic operations over semirings. Visit http://graphblas.org for more details and resources. See also the SuiteSparse:GraphBLAS User Guide in this package.

SuiteSparse:GraphBLAS, (c) 2017-2020, Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis

Contents

GraphBLAS: faster and more general sparse matrices for MATLAB

GraphBLAS is not only useful for creating graph algorithms; it also supports a wide range of sparse matrix data types and operations. MATLAB can compute C=A*B with just two semirings: 'plus.times.double' and 'plus.times.complex' for complex matrices. GraphBLAS has 1,473 unique built-in semirings, such as 'max.plus' (https://en.wikipedia.org/wiki/Tropical_semiring). These semirings can be used to construct a wide variety of graph algorithms, based on operations on sparse adjacency matrices.

MATLAB and GraphBLAS both provide sparse matrices of type double, logical, and double complex. GraphBLAS adds sparse matrices of type: single, int8, int16, int32, int64, uint8, uint16, uint32, uint64, and single complex (with MATLAB matrices, these types can only be held in full matrices).

clear
+GrB.clear
+format compact
+rng ('default') ;
+X = 100 * rand (2) ;
+G = GrB (X)              % GraphBLAS copy of a matrix X, same type
+
+G =
+
+  2x2 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)    81.4724
+    (2,1)    90.5792
+    (1,2)    12.6987
+    (2,2)    91.3376
+
+

Sparse integer matrices

Here's an int8 version of the same matrix:

S = int8 (G)            % convert G to a full MATLAB int8 matrix
+G = GrB (X, 'int8')      % a GraphBLAS sparse int8 matrix
+
S =
+  2x2 int8 matrix
+   81   13
+   91   91
+
+G =
+
+  2x2 GraphBLAS int8_t matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)   81
+    (2,1)   91
+    (1,2)   13
+    (2,2)   91
+
+

Sparse single-precision matrices

Matrix operations in GraphBLAS are typically as fast, or faster than MATLAB. Here's an unfair comparison: computing X^2 with MATLAB in double precision and with GraphBLAS in single precision. You would naturally expect GraphBLAS to be faster.

Please wait ...

n = 1e5 ;
+X = spdiags (rand (n, 201), -100:100, n, n) ;
+G = GrB (X, 'single') ;
+tic
+G2 = G^2 ;
+gb_time = toc ;
+tic
+X2 = X^2 ;
+matlab_time = toc ;
+fprintf ('\nGraphBLAS time: %g sec (in single)\n', gb_time) ;
+fprintf ('MATLAB time:    %g sec (in double)\n', matlab_time) ;
+fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
+    matlab_time / gb_time) ;
+
+GraphBLAS time: 1.60546 sec (in single)
+MATLAB time:    7.18249 sec (in double)
+Speedup of GraphBLAS over MATLAB: 4.47379
+

Mixing MATLAB and GraphBLAS matrices

The error in the last computation is about eps('single') since GraphBLAS did its computation in single precision, while MATLAB used double precision. MATLAB and GraphBLAS matrices can be easily combined, as in X2-G2. The sparse single precision matrices take less memory space.

err = norm (X2 - G2, 1) / norm (X2,1)
+eps ('single')
+whos G G2 X X2
+
err =
+   1.5049e-07
+ans =
+  single
+  1.1921e-07
+  Name           Size                    Bytes  Class     Attributes
+
+  G         100000x100000            241879724  GrB                 
+  G2        100000x100000            481518524  GrB                 
+  X         100000x100000            322238408  double    sparse    
+  X2        100000x100000            641756808  double    sparse    
+
+

Faster matrix operations

But even with standard double precision sparse matrices, GraphBLAS is typically faster than the built-in MATLAB methods. Here's a fair comparison:

G = GrB (X) ;
+tic
+G2 = G^2 ;
+gb_time = toc ;
+err = norm (X2 - G2, 1) / norm (X2,1)
+fprintf ('\nGraphBLAS time: %g sec (in double)\n', gb_time) ;
+fprintf ('MATLAB time:    %g sec (in double)\n', matlab_time) ;
+fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
+    matlab_time / gb_time) ;
+
err =
+     0
+
+GraphBLAS time: 1.76195 sec (in double)
+MATLAB time:    7.18249 sec (in double)
+Speedup of GraphBLAS over MATLAB: 4.07645
+

A wide range of semirings

MATLAB can only compute C=A*B using the standard '+.*.double' and '+.*.complex' semirings. A semiring is defined in terms of a string, 'add.mult.type', where 'add' is a monoid that takes the place of the additive operator, 'mult' is the multiplicative operator, and 'type' is the data type for the two inputs to the mult operator.

In the standard semiring, C=A*B is defined as:

C(i,j) = sum (A(i,:).' .* B(:,j))
+

using 'plus' as the monoid and 'times' as the multiplicative operator. But in a more general semiring, 'sum' can be any monoid, which is an associative and commutative operator that has an identity value. For example, in the 'max.plus' tropical algebra, C(i,j) for C=A*B is defined as:

C(i,j) = max (A(i,:).' + B(:,j))
+

This can be computed in GraphBLAS with:

C = GrB.mxm ('max.+', A, B)
+
n = 3 ;
+A = rand (n) ;
+B = rand (n) ;
+C = zeros (n) ;
+for i = 1:n
+    for j = 1:n
+        C(i,j) = max (A (i,:).' + B (:,j)) ;
+    end
+end
+C2 = GrB.mxm ('max.+', A, B) ;
+fprintf ('\nerr = norm (C-C2,1) = %g\n', norm (C-C2,1)) ;
+
+err = norm (C-C2,1) = 0
+

The max.plus tropical semiring

Here are details of the "max.plus" tropical semiring. The identity value is -inf since max(x,-inf) = max (-inf,x) = x for any x. The identity for the conventional "plus.times" semiring is zero, since x+0 = 0+x = x for any x.

GrB.semiringinfo ('max.+.double') ;
+
+    GraphBLAS Semiring: max.+.double (built-in)
+    GraphBLAS Monoid: semiring->add (built-in)
+    GraphBLAS BinaryOp: monoid->op (built-in) z=max(x,y)
+    GraphBLAS type: ztype double size: 8
+    GraphBLAS type: xtype double size: 8
+    GraphBLAS type: ytype double size: 8
+    identity: [    -Inf ] terminal: [    Inf ]
+
+    GraphBLAS BinaryOp: semiring->multiply (built-in) z=plus(x,y)
+    GraphBLAS type: ztype double size: 8
+    GraphBLAS type: xtype double size: 8
+    GraphBLAS type: ytype double size: 8
+

A boolean semiring

MATLAB cannot multiply two logical matrices. MATLAB R2019a converts them to double and uses the conventional +.*.double semiring instead. In GraphBLAS, this is the common Boolean 'or.and.logical' semiring, which is widely used in linear algebraic graph algorithms.

GrB.semiringinfo ('|.&.logical') ;
+
+    GraphBLAS Semiring: |.&.logical (built-in)
+    GraphBLAS Monoid: semiring->add (built-in)
+    GraphBLAS BinaryOp: monoid->op (built-in) z=or(x,y)
+    GraphBLAS type: ztype bool size: 1
+    GraphBLAS type: xtype bool size: 1
+    GraphBLAS type: ytype bool size: 1
+    identity: [   0 ] terminal: [   1 ]
+
+    GraphBLAS BinaryOp: semiring->multiply (built-in) z=and(x,y)
+    GraphBLAS type: ztype bool size: 1
+    GraphBLAS type: xtype bool size: 1
+    GraphBLAS type: ytype bool size: 1
+
clear
+A = sparse (rand (3) > 0.5)
+B = sparse (rand (3) > 0.2)
+
A =
+  3x3 sparse logical array
+   (2,1)      1
+   (2,2)      1
+   (3,2)      1
+   (1,3)      1
+B =
+  3x3 sparse logical array
+   (1,1)      1
+   (2,1)      1
+   (3,1)      1
+   (1,2)      1
+   (2,2)      1
+   (3,2)      1
+   (1,3)      1
+   (2,3)      1
+   (3,3)      1
+
try
+    % MATLAB R2019a does this by casting A and B to double
+    C1 = A*B
+catch
+    % MATLAB R2018a throws an error
+    fprintf ('MATLAB R2019a required for C=A*B with logical\n') ;
+    fprintf ('matrices.  Explicitly converting to double:\n') ;
+    C1 = double (A) * double (B)
+end
+C2 = GrB (A) * GrB (B)
+
C1 =
+   (1,1)        1
+   (2,1)        2
+   (3,1)        1
+   (1,2)        1
+   (2,2)        2
+   (3,2)        1
+   (1,3)        1
+   (2,3)        2
+   (3,3)        1
+
+C2 =
+
+  3x3 GraphBLAS bool matrix, sparse by col:
+  9 nonzeros, 9 entries
+
+    (1,1)   1
+    (2,1)   1
+    (3,1)   1
+    (1,2)   1
+    (2,2)   1
+    (3,2)   1
+    (1,3)   1
+    (2,3)   1
+    (3,3)   1
+
+

Note that C1 is a MATLAB sparse double matrix, and contains non-binary values. C2 is a GraphBLAS logical matrix.

whos
+GrB.type (C2)
+
  Name      Size            Bytes  Class      Attributes
+
+  A         3x3                68  logical    sparse    
+  B         3x3               113  logical    sparse    
+  C1        3x3               176  double     sparse    
+  C2        3x3              1031  GrB                  
+
+ans =
+    'logical'
+

GraphBLAS operators, monoids, and semirings

The C interface for SuiteSparse:GraphBLAS allows for arbitrary types and operators to be constructed. However, the MATLAB interface to SuiteSparse:GraphBLAS is restricted to pre-defined types and operators: a mere 13 types, 204 unary operators, 385 binary operators, 77 monoids, 16 select operators, and 2,438 semirings (1,473 of which are unique, since some binary operators are equivalent: 'min.logical' and '&.logical' are the same thing, for example).

That gives you a lot of tools to create all kinds of interesting graph algorithms. For example:

GrB.bfs    % breadth-first search
+GrB.dnn    % sparse deep neural network (http://graphchallenge.org)
+GrB.mis    % maximal independent set
+

See 'help GrB.binopinfo' for a list of the binary operators, and 'help GrB.monoidinfo' for the ones that can be used as the additive monoid in a semiring. 'help GrB.unopinfo' lists the unary operators.

help GrB.binopinfo
+
 GRB.BINOPINFO list the details of a GraphBLAS binary operator.
+ 
+    GrB.binopinfo
+    GrB.binopinfo (op)
+    GrB.binopinfo (op, optype)
+ 
+  Binary operators are defined by a string of the form 'op.optype', or
+  just 'op', where the optype is inferred from the operands.  Valid
+  optypes are 'logical', 'int8', 'int16', 'int32', 'int64', 'uint8',
+  'uint16', 'uint32', 'uint64', 'single', 'double', 'single complex',
+  'double complex' (the latter can be written as simply 'complex').
+ 
+  For GrB.binopinfo (op), the op must be a string of the form 'op.optype',
+  where 'op' is listed below.  The second usage allows the optype to be
+  omitted from the first argument, as just 'op'.  This is valid for all
+  GraphBLAS operations, since the optype can be determined from the
+  operands (see Typecasting, below).  However, GrB.binopinfo does not have
+  any operands and thus the optype must be provided, either in the op as
+  GrB.binopinfo ('+.double'), or in the second argument as
+  GrB.binopinfo ('+', 'double').
+ 
+  The 6 comparator operators come in two flavors.  For the is* operators,
+  the result has the same type as the inputs, x and y, with 1 for true and
+  0 for false.  For example isgt.double (pi, 3.0) is the double value 1.0.
+  For the second set of 6 operators (eq, ne, gt, lt, ge, le), the result
+  is always logical (true or false).  In a semiring, the optype of the add
+  monoid must exactly match the type of the output of the multiply
+  operator, and thus 'plus.iseq.double' is valid (counting how many terms
+  are equal).  The 'plus.eq.double' semiring is valid, but not the same
+  semiring since the 'plus' of 'plus.eq.double' has a logical type and is
+  thus equivalent to 'or.eq.double'.   The 'or.eq' is true if any terms
+  are equal and false otherwise (it does not count the number of terms
+  that are equal).
+ 
+  The following binary operators are available for most types.  Many have
+  equivalent synonyms, so that '1st' and 'first' both define the
+  first(x,y) = x operator.
+ 
+    operator name(s) f(x,y)         |   operator names(s) f(x,y)
+    ---------------- ------         |   ----------------- ------
+    1st first        x              |   iseq             x == y
+    2nd second       y              |   isne             x ~= y
+    min              min(x,y)       |   isgt             x > y
+    max              max(x,y)       |   islt             x < y
+    +   plus         x+y            |   isge             x >= y
+    -   minus        x-y            |   isle             x <= y
+    rminus           y-x            |   ==  eq           x == y
+    *   times        x*y            |   ~=  ne           x ~= y
+    /   div          x/y            |   >   gt           x > y
+    \   rdiv         y/x            |   <   lt           x < y
+    |   || or  lor   x | y          |   >=  ge           x >= y
+    &   && and land  x & y          |   <=  le           x <= y
+    xor lxor         xor(x,y)       |   .^  pow          x .^ y
+    pair             1              |   any              pick x or y
+ 
+  Comparators (*lt, *gt, *le, *ge) and min/max are not available for
+  complex types.
+ 
+  All of the above operators are defined for logical operands, but many
+  are redundant. 'min.logical' is the same as 'and.logical', for example.
+  Most of the logical operators have aliases: ('lor', 'or', '|') are the
+  same, as are ('lxnor', 'xnor', 'eq', '==') for logical types.
+ 
+  The three logical operators, lor, land, and lxor, can be used with any
+  real types.  z = lor.double (x,y) tests the condition (x~=0) || (y~=0),
+  and returns the double value 1.0 if true, or 0.0 if false.
+ 
+  The following operators are avaiable for single and double (real); their
+  definitions are identical to the ANSI C11 versions of these functions:
+  atan2, hypot, fmod, remainder, copysign, ldxep (also called 'pow2').
+  All produce the same type as the input, on output.
+ 
+  z = cmplx(x,y) can be computed for x and y as single and double; z is
+  single complex or double complex, respectively.
+ 
+  The following bitwise operators are available for any signed or
+  unsigned integer types:  bitor, bitand, bitxor, bitxnor, bitget, bitset,
+  bitclr, and bitshift.
+ 
+  Typecasting:  If the optype is omitted from the string (for example,
+  GrB.eadd (A, '+', B) or simply C = A+B), then the optype is inferred
+  from the type of A and B.  See 'help GrB.optype' for details.
+ 
+  Example:
+ 
+    % valid binary operators
+    GrB.binopinfo ('+.double') ;    % also a valid unary operator
+    GrB.binopinfo ('1st.int32') ;
+    GrB.binopinfo ('cmplx.single') ;
+    GrB.binopinfo ('pow2.double') ; % also a valid unary operator
+    GrB.unopinfo  ('pow2.double') ;
+ 
+    % invalid binary operator (an error; this is a unary op):
+    GrB.binopinfo ('abs.double') ;
+ 
+  See also GrB.descriptorinfo, GrB.monoidinfo, GrB.selectopinfo,
+  GrB.semiringinfo, GrB.unopinfo, GrB.optype.
+
+
help GrB.monoidinfo
+
 GRB.MONOIDINFO list the details of a GraphBLAS monoid.
+ 
+    GrB.monoidinfo
+    GrB.monoidinfo (monoid)
+    GrB.monoidinfo (monoid, type)
+ 
+  For GrB.monoidinfo(op), the op must be a string of the form 'op.type',
+  where 'op' is listed below.  The second usage allows the type to be
+  omitted from the first argument, as just 'op'.  This is valid for all
+  GraphBLAS operations, since the type defaults to the type of the input
+  matrices.  However, GrB.monoidinfo does not have a default type and thus
+  one must be provided, either in the op as GrB.monoidinfo ('+.double'), or
+  in the second argument, GrB.monoidinfo ('+', 'double').
+ 
+  A monoid is any binary operator z=f(x,y) that is commutative and
+  associative, with an identity value o so that f(x,o)=f(o,x)=o.  The types
+  of z, x, and y must all be identical.  For example, the plus.double
+  operator is f(x,y)=x+y, with zero as the identity value (x+0 = 0+x = x).
+  The times monoid has an identity value of 1 (since x*1 = 1*x = x).  The
+  identity of min.double is -inf.
+ 
+  The valid monoids for real non-logical types are:
+        '+', '*', 'max', 'min', 'any'
+  For the 'logical' type:
+        '|', '&', 'xor', 'eq', 'any'
+  For complex types:
+        '+', '*', 'any'
+  For integer types (signed and unsigned):
+        'bitor', 'bitand', 'bitxor', 'bitxnor'
+ 
+  Some monoids have synonyms; see 'help GrB.binopinfo' for details.
+ 
+  Example:
+ 
+    % valid monoids
+    GrB.monoidinfo ('+.double') ;
+    GrB.monoidinfo ('*.int32') ;
+    GrB.monoidinfo ('min.double') ;
+ 
+    % invalid monoids
+    GrB.monoidinfo ('1st.int32') ;
+    GrB.monoidinfo ('abs.double') ;
+    GrB.monoidinfo ('min.complex') ;
+ 
+  See also GrB.binopinfo, GrB.descriptorinfo, GrB.selectopinfo,
+  GrB.semiringinfo, GrB.unopinfo.
+
+
help GrB.unopinfo
+
 GRB.UNOPINFO list the details of a GraphBLAS unary operator.
+ 
+    GrB.unopinfo
+    GrB.unopinfo (op)
+    GrB.unopinfo (op, type)
+ 
+  For GrB.unopinfo(op), the op must be a string of the form 'op.type',
+  where 'op' is listed below.  The second usage allows the type to be
+  omitted from the first argument, as just 'op'.  This is valid for all
+  GraphBLAS operations, since the type defaults to the type of the input
+  matrix.  However, GrB.unopinfo does not have a default type and thus one
+  must be provided, either in the op as GrB.unopinfo ('abs.double'), or in
+  the second argument, GrB.unopinfo ('abs', 'double').
+ 
+  The functions z=f(x) are listed below.  Unless otherwise specified,
+  z and x have the same type.  Some functions have synonyms, as listed.
+ 
+  For all 13 types:
+    identity    z = x       also '+', 'uplus'
+    ainv        z = -x      additive inverse, also '-', 'negate', 'uminus'
+    minv        z = 1/x     multiplicative inverse
+    one         z = 1       does not depend on x, also '1'
+    abs         z = |x|     'abs.complex' returns a real result
+ 
+  For all 11 real types:
+    lnot        z = ~(x ~= 0)   logical negation (z is 1 or 0, with the
+                                same type as x), also '~', 'not'.
+ 
+  For 4 floating-point types (real & complex)x(single & double):
+    sqrt        z = sqrt (x)    square root
+    log         z = log (x)     base-e logarithm
+    log2        z = log2 (x)    base-2 logarithm
+    log10       z = log10 (x)   base-10 logarithm
+    log1p       z = log1p (x)   log (x-1), base-e
+    exp         z = exp (x)     base-e exponential, e^x
+    pow2        z = pow2 (x)    base-2 exponential, 2^x
+    expm1       z = exp1m (x)   e^x-1
+    sin         z = sin (x)     sine
+    cos         z = cos (x)     cosine
+    tan         z = tan (x)     tangent
+    acos        z = acos (x)    arc cosine
+    asin        z = asin (x)    arc sine
+    atan        z = atan (x)    arc tangent
+    sinh        z = sinh (x)    hyperbolic sine
+    cosh        z = cosh (x)    hyperbolic cosine
+    tanh        z = tanh (x)    hyperbolic tangent
+    asinh       z = asinh (x)   inverse hyperbolic sine
+    acosh       z = acosh (x)   inverse hyperbolic cosine
+    atanh       z = atanh (x)   inverse hyperbolic tangent
+    signum      z = signum (x)  signum function, also 'sign'
+    ceil        z = ceil (x)    ceiling
+    floor       z = floor (x)   floor
+    round       z = round (x)   round to nearest
+    trunc       z = trunc (x)   truncate, also 'fix'
+ 
+  For 'single complex' and 'double complex' only:
+    creal       z = real (x)    real part of x (z is real), also 'real'
+    cimag       z = imag (x)    imag. part of x (z is real), also 'imag'
+    carg        z = carg (x)    phase angle (z is real), also 'angle'
+    conj        z = conj (x)    complex conjugate (z is complex)
+ 
+  For all 4 floating-point types (result is logical):
+    isinf       z = isinf (x)       true if x is +Inf or -Inf
+    isnan       z = isnan (x)       true if x is NaN
+    isfinite    z = isfinite (x)    true if x is finite
+ 
+  For single and double (result same type as input):
+    lgamma      z = lgamma (x)  log of gamma function, also 'gammaln'
+    tgamma      z = tgamma (x)  gamma function, also 'gamma'
+    erf         z = erf (x)     error function
+    erfc        z = erfc (x)    complementary error function
+    frexpx      z = frexpx (x)  mantissa from ANSI C11 frexp function
+    frexpe      z = frexpe (x)  exponent from ANSI C11 frexp function
+                                The MATLAB [f,e]=log2(x) returns
+                                f = frexpx (x) and e = frexpe (x).
+ 
+  For integer types only (result is same type as input):
+    bitcmp      z = ~(x)        bitwise complement, also 'bitnot'
+ 
+  Example:
+ 
+    % valid unary operators
+    GrB.unopinfo ('+.double') ;     % also a valid binary operator
+    GrB.unopinfo ('abs.double') ;
+    GrB.unopinfo ('not.int32') ;
+    GrB.unopinfo ('pow2.double') ;  % also a valid binary operator
+    GrB.binopinfo ('pow2.double') ;
+ 
+    % invalid unary operator (generates an error; this is a binary op):
+    GrB.unopinfo ('*.double') ;
+ 
+  See also GrB.binopinfo, GrB.descriptorinfo, GrB.monoidinfo,
+  GrB.selectopinfo, GrB.semiringinfo.
+
+

Element-wise operations

Binary operators can be used in element-wise matrix operations, like C=A+B and C=A.*B. For the matrix addition C=A+B, the pattern of C is the set union of A and B, and the '+' operator is applied for entries in the intersection. Entries in A but not B, or in B but not A, are assigned to C without using the operator. The '+' operator is used for C=A+B but any operator can be used with GrB.eadd.

A = GrB (sprand (3, 3, 0.5)) ;
+B = GrB (sprand (3, 3, 0.5)) ;
+C1 = A + B
+C2 = GrB.eadd ('+', A, B)
+err = norm (C1-C2,1)
+
+C1 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  7 nonzeros, 7 entries
+
+    (1,1)    0.666139
+    (3,1)    0.735859
+    (1,2)    1.47841
+    (2,2)    0.146938
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+
+C2 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  7 nonzeros, 7 entries
+
+    (1,1)    0.666139
+    (3,1)    0.735859
+    (1,2)    1.47841
+    (2,2)    0.146938
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+err =
+     0
+

Subtracting two matrices

A-B and GrB.eadd ('-', A, B) are not the same thing, since the '-' operator is not applied to an entry that is in B but not A.

C1 = A-B
+C2 = GrB.eadd ('-', A, B)
+
+C1 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  7 nonzeros, 7 entries
+
+    (1,1)    -0.666139
+    (3,1)    -0.735859
+    (1,2)    -0.334348
+    (2,2)    -0.146938
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+
+C2 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  7 nonzeros, 7 entries
+
+    (1,1)    0.666139
+    (3,1)    0.735859
+    (1,2)    -0.334348
+    (2,2)    0.146938
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+

But these give the same result

C1 = A-B
+C2 = GrB.eadd ('+', A, GrB.apply ('-', B))
+err = norm (C1-C2,1)
+
+C1 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  7 nonzeros, 7 entries
+
+    (1,1)    -0.666139
+    (3,1)    -0.735859
+    (1,2)    -0.334348
+    (2,2)    -0.146938
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+
+C2 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  7 nonzeros, 7 entries
+
+    (1,1)    -0.666139
+    (3,1)    -0.735859
+    (1,2)    -0.334348
+    (2,2)    -0.146938
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+err =
+     0
+

Element-wise 'multiplication'

For C = A.*B, the result C is the set intersection of the pattern of A and B. The operator is applied to entries in both A and B. Entries in A but not B, or B but not A, do not appear in the result C.

C1 = A.*B
+C2 = GrB.emult ('*', A, B)
+C3 = double (A) .* double (B)
+
+C1 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  1 nonzero, 1 entry
+
+    (1,2)    0.518474
+
+
+C2 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  1 nonzero, 1 entry
+
+    (1,2)    0.518474
+
+C3 =
+   (1,2)       0.5185
+

Just as in GrB.eadd, any operator can be used in GrB.emult:

A
+B
+C2 = GrB.emult ('max', A, B)
+
+A =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,2)    0.572029
+    (3,2)    0.566879
+    (2,3)    0.248635
+    (3,3)    0.104226
+
+
+B =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)    0.666139
+    (3,1)    0.735859
+    (1,2)    0.906378
+    (2,2)    0.146938
+
+
+C2 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  1 nonzero, 1 entry
+
+    (1,2)    0.906378
+
+

Overloaded operators

The following operators all work as you would expect for any matrix. The matrices A and B can be GraphBLAS matrices, or MATLAB sparse or dense matrices, in any combination, or scalars where appropriate, The matrix M is logical (MATLAB or GraphBLAS):

  A+B   A-B  A*B   A.*B  A./B  A.\B  A.^b   A/b   C=A(I,J)  C(M)=A
+  -A    +A   ~A    A'    A.'   A&B   A|B    b\A   C(I,J)=A  C=A(M)
+  A~=B  A>B  A==B  A<=B  A>=B  A<B   [A,B]  [A;B] C(A)
+  A(1:end,1:end)

For A^b, b must be a non-negative integer.

C1 = [A B] ;
+C2 = [double(A) double(B)] ;
+assert (isequal (double (C1), C2))
+
C1 = A^2
+C2 = double (A)^2 ;
+err = norm (C1 - C2, 1)
+assert (err < 1e-12)
+
+C1 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  5 nonzeros, 5 entries
+
+    (2,2)    0.140946
+    (3,2)    0.0590838
+    (1,3)    0.142227
+    (2,3)    0.0259144
+    (3,3)    0.151809
+
+err =
+     0
+
C1 = A (1:2,2:end)
+A = double (A) ;
+C2 = A (1:2,2:end) ;
+assert (isequal (double (C1), C2))
+
+C1 =
+
+  2x2 GraphBLAS double matrix, sparse by col:
+  2 nonzeros, 2 entries
+
+    (1,1)    0.572029
+    (2,2)    0.248635
+
+

Overloaded functions

Many MATLAB built-in functions can be used with GraphBLAS matrices:

A few differences with the built-in functions:

S = sparse (G)        % makes a copy of a GrB matrix
+F = full (G)          % adds explicit zeros, so numel(F)==nnz(F)
+F = full (G,type,id)  % adds explicit identity values to a GrB matrix
+disp (G, level)       % display a GrB matrix G; level=2 is the default.
+

In the list below, the first set of Methods are overloaded built-in methods. They are used as-is on GraphBLAS matrices, such as C=abs(G). The Static methods are prefixed with "GrB.", as in C = GrB.apply ( ... ).

methods GrB
+
+Methods for class GrB:
+
+GrB             disp            islogical       real            
+abs             display         ismatrix        repmat          
+acos            dmperm          isnan           reshape         
+acosh           double          isnumeric       round           
+acot            eig             isreal          sec             
+acoth           end             isscalar        sech            
+acsc            eps             issparse        sign            
+acsch           eq              issymmetric     sin             
+all             erf             istril          single          
+amd             erfc            istriu          sinh            
+and             etree           isvector        size            
+angle           exp             kron            sparse          
+any             expm1           ldivide         spfun           
+asec            false           le              spones          
+asech           find            length          sprand          
+asin            fix             log             sprandn         
+asinh           flip            log10           sprandsym       
+assert          floor           log1p           sprintf         
+atan            fprintf         log2            sqrt            
+atan2           full            logical         subsasgn        
+atanh           gamma           lt              subsindex       
+bandwidth       gammaln         max             subsref         
+bitand          ge              min             sum             
+bitcmp          graph           minus           symamd          
+bitget          gt              mldivide        symrcm          
+bitor           horzcat         mpower          tan             
+bitset          hypot           mrdivide        tanh            
+bitshift        imag            mtimes          times           
+bitxor          int16           ne              transpose       
+ceil            int32           nnz             tril            
+colamd          int64           nonzeros        triu            
+complex         int8            norm            true            
+conj            isa             not             uint16          
+cos             isbanded        numel           uint32          
+cosh            isdiag          nzmax           uint64          
+cot             isempty         ones            uint8           
+coth            isequal         or              uminus          
+csc             isfinite        plus            uplus           
+csch            isfloat         pow2            vertcat         
+ctranspose      ishermitian     power           xor             
+diag            isinf           prod            zeros           
+digraph         isinteger       rdivide         
+
+Static methods:
+
+MATLAB_vs_GrB   empty           issigned        reduce          
+apply           emult           kronecker       select          
+apply2          entries         ktruss          selectopinfo    
+assign          expand          laplacian       semiringinfo    
+bfs             extract         mis             speye           
+binopinfo       extracttuples   monoidinfo      subassign       
+build           eye             mxm             threads         
+burble          finalize        nonz            trans           
+chunk           format          normdiff        tricount        
+clear           incidence       offdiag         type            
+compact         init            optype          unopinfo        
+descriptorinfo  isbycol         pagerank        vreduce         
+dnn             isbyrow         prune           
+eadd            isfull          random          
+
+

Zeros are handled differently

Explicit zeros cannot be automatically dropped from a GraphBLAS matrix, like they are in MATLAB sparse matrices. In a shortest-path problem, for example, an edge A(i,j) that is missing has an infinite weight, (the monoid identity of min(x,y) is +inf). A zero edge weight A(i,j)=0 is very different from an entry that is not present in A. However, if a GraphBLAS matrix is converted into a MATLAB sparse matrix, explicit zeros are dropped, which is the convention for a MATLAB sparse matrix. They can also be dropped from a GraphBLAS matrix using the GrB.select method.

G = GrB (magic (2)) ;
+G (1,1) = 0      % G(1,1) still appears as an explicit entry
+A = double (G)   % but it's dropped when converted to MATLAB sparse
+H = GrB.select ('nonzero', G)  % drops the explicit zeros from G
+fprintf ('nnz (G): %d  nnz (A): %g nnz (H): %g\n', ...
+    nnz (G), nnz (A), nnz (H)) ;
+fprintf ('num entries in G: %d\n', GrB.entries (G)) ;
+
+G =
+
+  2x2 GraphBLAS double matrix, sparse by col:
+  3 nonzeros, 4 entries
+
+    (1,1)    0
+    (2,1)    4
+    (1,2)    3
+    (2,2)    2
+
+A =
+   (2,1)        4
+   (1,2)        3
+   (2,2)        2
+
+H =
+
+  2x2 GraphBLAS double matrix, sparse by col:
+  3 nonzeros, 3 entries
+
+    (2,1)    4
+    (1,2)    3
+    (2,2)    2
+
+nnz (G): 3  nnz (A): 3 nnz (H): 3
+num entries in G: 4
+

Displaying contents of a GraphBLAS matrix

Unlike MATLAB, the default is to display just a few entries of a GrB matrix. Here are all 100 entries of a 10-by-10 matrix, using a non-default disp(G,3):

G = GrB (rand (10)) ;
+% display everything:
+disp (G,3)
+
+G =
+
+  10x10 GraphBLAS double matrix, sparse by col:
+  100 nonzeros, 100 entries
+
+    (1,1)    0.0342763
+    (2,1)    0.17802
+    (3,1)    0.887592
+    (4,1)    0.889828
+    (5,1)    0.769149
+    (6,1)    0.00497062
+    (7,1)    0.735693
+    (8,1)    0.488349
+    (9,1)    0.332817
+    (10,1)    0.0273313
+    (1,2)    0.467212
+    (2,2)    0.796714
+    (3,2)    0.849463
+    (4,2)    0.965361
+    (5,2)    0.902248
+    (6,2)    0.0363252
+    (7,2)    0.708068
+    (8,2)    0.322919
+    (9,2)    0.700716
+    (10,2)    0.472957
+    (1,3)    0.204363
+    (2,3)    0.00931977
+    (3,3)    0.565881
+    (4,3)    0.183435
+    (5,3)    0.00843818
+    (6,3)    0.284938
+    (7,3)    0.706156
+    (8,3)    0.909475
+    (9,3)    0.84868
+    (10,3)    0.564605
+    (1,4)    0.075183
+    (2,4)    0.535293
+    (3,4)    0.072324
+    (4,4)    0.515373
+    (5,4)    0.926149
+    (6,4)    0.949252
+    (7,4)    0.0478888
+    (8,4)    0.523767
+    (9,4)    0.167203
+    (10,4)    0.28341
+    (1,5)    0.122669
+    (2,5)    0.441267
+    (3,5)    0.157113
+    (4,5)    0.302479
+    (5,5)    0.758486
+    (6,5)    0.910563
+    (7,5)    0.0246916
+    (8,5)    0.232421
+    (9,5)    0.38018
+    (10,5)    0.677531
+    (1,6)    0.869074
+    (2,6)    0.471459
+    (3,6)    0.624929
+    (4,6)    0.987186
+    (5,6)    0.282885
+    (6,6)    0.843833
+    (7,6)    0.869597
+    (8,6)    0.308209
+    (9,6)    0.201332
+    (10,6)    0.706603
+    (1,7)    0.563222
+    (2,7)    0.575795
+    (3,7)    0.056376
+    (4,7)    0.73412
+    (5,7)    0.608022
+    (6,7)    0.0400164
+    (7,7)    0.540801
+    (8,7)    0.023064
+    (9,7)    0.165682
+    (10,7)    0.250393
+    (1,8)    0.23865
+    (2,8)    0.232033
+    (3,8)    0.303191
+    (4,8)    0.579934
+    (5,8)    0.267751
+    (6,8)    0.916376
+    (7,8)    0.833499
+    (8,8)    0.978692
+    (9,8)    0.734445
+    (10,8)    0.102896
+    (1,9)    0.353059
+    (2,9)    0.738955
+    (3,9)    0.57539
+    (4,9)    0.751433
+    (5,9)    0.93256
+    (6,9)    0.281622
+    (7,9)    0.51302
+    (8,9)    0.24406
+    (9,9)    0.950086
+    (10,9)    0.303638
+    (1,10)    0.563593
+    (2,10)    0.705101
+    (3,10)    0.0604146
+    (4,10)    0.672065
+    (5,10)    0.359793
+    (6,10)    0.62931
+    (7,10)    0.977758
+    (8,10)    0.394328
+    (9,10)    0.765651
+    (10,10)    0.457809
+
+
+

That was disp(G,3), so every entry was printed. It's a little long, so the default is not to print everything.

With the default display (level = 2):

G
+
+G =
+
+  10x10 GraphBLAS double matrix, sparse by col:
+  100 nonzeros, 100 entries
+
+    (1,1)    0.0342763
+    (2,1)    0.17802
+    (3,1)    0.887592
+    (4,1)    0.889828
+    (5,1)    0.769149
+    (6,1)    0.00497062
+    (7,1)    0.735693
+    (8,1)    0.488349
+    (9,1)    0.332817
+    (10,1)    0.0273313
+    (1,2)    0.467212
+    (2,2)    0.796714
+    (3,2)    0.849463
+    (4,2)    0.965361
+    (5,2)    0.902248
+    (6,2)    0.0363252
+    (7,2)    0.708068
+    (8,2)    0.322919
+    (9,2)    0.700716
+    (10,2)    0.472957
+    (1,3)    0.204363
+    (2,3)    0.00931977
+    (3,3)    0.565881
+    (4,3)    0.183435
+    (5,3)    0.00843818
+    (6,3)    0.284938
+    (7,3)    0.706156
+    (8,3)    0.909475
+    (9,3)    0.84868
+    (10,3)    0.564605
+    ...
+
+

That was disp(G,2) or just display(G), which is what is printed by a MATLAB statement that doesn't have a trailing semicolon. With level = 1, disp(G,1) gives just a terse summary:

disp (G,1)
+
+G =
+
+  10x10 GraphBLAS double matrix, sparse by col:
+  100 nonzeros, 100 entries
+
+
+

Storing a matrix by row or by column

MATLAB stores its sparse matrices by column, refered to as 'standard CSC' in SuiteSparse:GraphBLAS. In the CSC (compressed sparse column) format, each column of the matrix is stored as a list of entries, with their value and row index. In the CSR (compressed sparse row) format, each row is stored as a list of values and their column indices. GraphBLAS uses both CSC and CSR, and the two formats can be intermixed arbitrarily. In its C interface, the default format is CSR. However, for better compatibility with MATLAB, this MATLAB interface for SuiteSparse:GraphBLAS uses CSC by default instead.

rng ('default') ;
+GrB.clear ;                      % clear prior GraphBLAS settings
+fprintf ('the default format is: %s\n', GrB.format) ;
+C = sparse (rand (2))
+G = GrB (C)
+GrB.format (G)
+
the default format is: by col
+C =
+   (1,1)       0.8147
+   (2,1)       0.9058
+   (1,2)       0.1270
+   (2,2)       0.9134
+
+G =
+
+  2x2 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)    0.814724
+    (2,1)    0.905792
+    (1,2)    0.126987
+    (2,2)    0.913376
+
+ans =
+    'by col'
+

Many graph algorithms work better in CSR format, with matrices stored by row. For example, it is common to use A(i,j) for the edge (i,j), and many graph algorithms need to access the out-adjacencies of nodes, which is the row A(i,;) for node i. If the CSR format is desired, GrB.format ('by row') tells GraphBLAS to create all subsequent matrices in the CSR format. Converting from a MATLAB sparse matrix (in standard CSC format) takes a little more time (requiring a transpose), but subsequent graph algorithms can be faster.

G = GrB (C, 'by row')
+fprintf ('the format of G is:    %s\n', GrB.format (G)) ;
+H = GrB (C)
+fprintf ('the format of H is:    %s\n', GrB.format (H)) ;
+err = norm (H-G,1)
+
+G =
+
+  2x2 GraphBLAS double matrix, sparse by row:
+  4 nonzeros, 4 entries
+
+    (1,1)    0.814724
+    (1,2)    0.126987
+    (2,1)    0.905792
+    (2,2)    0.913376
+
+the format of G is:    by row
+
+H =
+
+  2x2 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)    0.814724
+    (2,1)    0.905792
+    (1,2)    0.126987
+    (2,2)    0.913376
+
+the format of H is:    by col
+err =
+     0
+

Hypersparse matrices

SuiteSparse:GraphBLAS can use two kinds of sparse matrix data structures: standard and hypersparse, for both CSC and CSR formats. In the standard CSC format used in MATLAB, an m-by-n matrix A takes O(n+nnz(A)) space. MATLAB can create huge column vectors, but not huge matrices (when n is huge).

clear
+[c, huge] = computer ;
+C = sparse (huge, 1)    % MATLAB can create a huge-by-1 sparse column
+try
+    C = sparse (huge, huge)     % but this fails
+catch me
+    error_expected = me
+end
+
C =
+   All zero sparse: 281474976710655x1
+error_expected = 
+  MException with properties:
+
+    identifier: 'MATLAB:array:SizeLimitExceeded'
+       message: 'Requested 281474976710655x281474976710655 (2097152.0GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive.'
+         cause: {}
+         stack: [4x1 struct]
+    Correction: []
+

In a GraphBLAS hypersparse matrix, an m-by-n matrix A takes only O(nnz(A)) space. The difference can be huge if nnz (A) << n.

clear
+[c, huge] = computer ;
+G = GrB (huge, 1)            % no problem for GraphBLAS
+H = GrB (huge, huge)         % this works in GraphBLAS too
+
+G =
+
+  281474976710655x1 GraphBLAS double matrix, sparse by col:
+  no nonzeros, no entries
+
+
+H =
+
+  281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
+  no nonzeros, no entries
+
+

Operations on huge hypersparse matrices are very fast; no component of the time or space complexity is Omega(n).

I = randperm (huge, 2) ;
+J = randperm (huge, 2) ;
+H (I,J) = magic (2) ;        % add 4 nonzeros to random locations in H
+H (I,I) = 10 * [1 2 ; 3 4] ; % so H^2 is not all zero
+H = H^2 ;                    % square H
+H = (H' * 2) ;               % transpose H and double the entries
+K = pi * spones (H) ;
+H = H + K                    % add pi to each entry in H
+
+H =
+
+  281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
+  8 nonzeros, 8 entries
+
+    (27455183225557,27455183225557)    4403.14
+    (78390279669562,27455183225557)    383.142
+    (153933462881710,27455183225557)    343.142
+    (177993304104065,27455183225557)    3003.14
+    (27455183225557,177993304104065)    2003.14
+    (78390279669562,177993304104065)    183.142
+    (153933462881710,177993304104065)    143.142
+    (177993304104065,177993304104065)    1403.14
+
+

numel uses vpa if the matrix is really huge

e1 = numel (G)               % this is huge, but still a flint
+e2 = numel (H)               % this is huge^2, which needs vpa
+whos e1 e2
+
e1 =
+   2.8147e+14
+e2 =
+79228162514263774643590529025.0
+  Name      Size            Bytes  Class     Attributes
+
+  e1        1x1                 8  double              
+  e2        1x1                 8  sym                 
+
+

All of these matrices take very little memory space:

whos C G H K
+
  Name                    Size                         Bytes  Class    Attributes
+
+  G         281474976710655x1                            941  GrB                
+  H         281474976710655x281474976710655             1252  GrB                
+  K         281474976710655x281474976710655             1252  GrB                
+
+

The mask and accumulator

When not used in overloaded operators or built-in functions, many GraphBLAS methods of the form GrB.method ( ... ) can optionally use a mask and/or an accumulator operator. If the accumulator is '+' in GrB.mxm, for example, then C = C + A*B is computed. The mask acts much like logical indexing in MATLAB. With a logical mask matrix M, C<M>=A*B allows only part of C to be assigned. If M(i,j) is true, then C(i,j) can be modified. If false, then C(i,j) is not modified.

For example, to set all values in C that are greater than 0.5 to 3:

A = rand (3)
+C = GrB.assign (A, A > 0.5, 3) ;     % in GraphBLAS
+C1 = GrB (A) ; C1 (A > .5) = 3       % also in GraphBLAS
+C2 = A       ; C2 (A > .5) = 3       % in MATLAB
+err = norm (C - C1, 1)
+err = norm (C - C2, 1)
+
A =
+    0.9575    0.9706    0.8003
+    0.9649    0.9572    0.1419
+    0.1576    0.4854    0.4218
+
+C1 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  9 nonzeros, 9 entries
+
+    (1,1)    3
+    (2,1)    3
+    (3,1)    0.157613
+    (1,2)    3
+    (2,2)    3
+    (3,2)    0.485376
+    (1,3)    3
+    (2,3)    0.141886
+    (3,3)    0.421761
+
+C2 =
+    3.0000    3.0000    3.0000
+    3.0000    3.0000    0.1419
+    0.1576    0.4854    0.4218
+err =
+     0
+err =
+     0
+

The descriptor

Most GraphBLAS functions of the form GrB.method ( ... ) take an optional last argument, called the descriptor. It is a MATLAB struct that can modify the computations performed by the method. 'help GrB.descriptorinfo' gives all the details. The following is a short summary of the primary settings:

d.out = 'default' or 'replace', clears C after the accum op is used.

d.mask = 'default' or 'complement', to use M or ~M as the mask matrix; 'structural', or 'structural complement', to use the pattern of M or ~M.

d.in0 = 'default' or 'transpose', to transpose A for C=A*B, C=A+B, etc.

d.in1 = 'default' or 'transpose', to transpose B for C=A*B, C=A+B, etc.

d.kind = 'default', 'GrB', 'sparse', or 'full'; the output of GrB.method.

A = sparse (rand (2)) ;
+B = sparse (rand (2)) ;
+C1 = A'*B ;
+C2 = GrB.mxm ('+.*', A, B, struct ('in0', 'transpose')) ;
+err = norm (C1-C2,1)
+
err =
+     0
+

Integer arithmetic is different in GraphBLAS

MATLAB supports integer arithmetic on its full matrices, using int8, int16, int32, int64, uint8, uint16, uint32, or uint64 data types. None of these integer data types can be used to construct a MATLAB sparse matrix, which can only be double, double complex, or logical. Furthermore, C=A*B is not defined for integer types in MATLAB, except when A and/or B are scalars.

GraphBLAS supports all of those types for its sparse matrices. All operations are supported, including C=A*B when A or B are any integer type, in 1000s of semirings.

However, integer arithmetic differs in GraphBLAS and MATLAB. In MATLAB, integer values saturate if they exceed their maximum value. In GraphBLAS, integer operators act in a modular fashion. The latter is essential when computing C=A*B over a semiring. A saturating integer operator cannot be used as a monoid since it is not associative.

C = uint8 (magic (3)) ;
+G = GrB (C) ;
+C1 = C * 40
+C2 = G * uint8 (40)
+S = double (C1 < 255) ;
+assert (isequal (double (C1).*S, double (C2).*S))
+
C1 =
+  3x3 uint8 matrix
+   255    40   240
+   120   200   255
+   160   255    80
+
+C2 =
+
+  3x3 GraphBLAS uint8_t matrix, sparse by col:
+  9 nonzeros, 9 entries
+
+    (1,1)   64
+    (2,1)   120
+    (3,1)   160
+    (1,2)   40
+    (2,2)   200
+    (3,2)   104
+    (1,3)   240
+    (2,3)   24
+    (3,3)   80
+
+

An example graph algorithm: breadth-first search

The breadth-first search of a graph finds all nodes reachable from the source node, and their level, v. v=GrB.bfs(A,s) or v=bfs_matlab(A,s) compute the same thing, but GrB.bfs uses GraphBLAS matrices and operations, while bfs_matlab uses pure MATLAB operations. v is defined as v(s) = 1 for the source node, v(i) = 2 for nodes adjacent to the source, and so on.

clear
+rng ('default') ;
+n = 1e5 ;
+A = logical (sprandn (n, n, 1e-3)) ;
+
+tic
+v1 = GrB.bfs (A, 1) ;
+gb_time = toc ;
+
+tic
+v2 = bfs_matlab (A, 1) ;
+matlab_time = toc ;
+
+assert (isequal (double (v1'), v2))
+fprintf ('\nnodes reached: %d of %d\n', nnz (v2), n) ;
+fprintf ('GraphBLAS time: %g sec\n', gb_time) ;
+fprintf ('MATLAB time:    %g sec\n', matlab_time) ;
+fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
+    matlab_time / gb_time) ;
+
+nodes reached: 100000 of 100000
+GraphBLAS time: 0.278521 sec
+MATLAB time:    0.464127 sec
+Speedup of GraphBLAS over MATLAB: 1.6664
+

Example graph algorithm: Luby's method in GraphBLAS

The GrB.mis function is variant of Luby's randomized algorithm [Luby 1985]. It is a parallel method for finding an maximal independent set of nodes, where no two nodes are adjacent. See the GraphBLAS/@GrB/mis.m function for details. The graph must be symmetric with a zero-free diagonal, so A is symmetrized first and any diagonal entries are removed.

A = GrB (A) ;
+A = GrB.offdiag (A|A') ;
+
+tic
+s = GrB.mis (A) ;
+toc
+fprintf ('# nodes in the graph: %g\n', size (A,1)) ;
+fprintf ('# edges: : %g\n', GrB.entries (A) / 2) ;
+fprintf ('size of maximal independent set found: %g\n', ...
+    full (double (sum (s)))) ;
+
+% make sure it's independent
+p = find (s) ;
+S = A (p,p) ;
+assert (GrB.entries (S) == 0)
+
+% make sure it's maximal
+notp = find (s == 0) ;
+S = A (notp, p) ;
+deg = GrB.vreduce ('+.int64', S) ;
+assert (logical (all (deg > 0)))
+
Elapsed time is 0.327699 seconds.
+# nodes in the graph: 100000
+# edges: : 9.9899e+06
+size of maximal independent set found: 2811
+

Sparse deep neural network

The 2019 MIT GraphChallenge (see http://graphchallenge.org) is to solve a set of large sparse deep neural network problems. In this demo, the MATLAB reference solution is compared with a solution using GraphBLAS, for a randomly constructed neural network. See the GrB.dnn and dnn_matlab.m functions for details.

clear
+rng ('default') ;
+nlayers = 16 ;
+nneurons = 4096 ;
+nfeatures = 30000 ;
+fprintf ('# layers:   %d\n', nlayers) ;
+fprintf ('# neurons:  %d\n', nneurons) ;
+fprintf ('# features: %d\n', nfeatures) ;
+
+tic
+Y0 = sprand (nfeatures, nneurons, 0.1) ;
+for layer = 1:nlayers
+    W {layer} = sprand (nneurons, nneurons, 0.01) * 0.2 ;
+    bias {layer} = -0.2 * ones (1, nneurons) ;
+end
+t_setup = toc ;
+fprintf ('construct problem time: %g sec\n', t_setup) ;
+
+% convert the problem from MATLAB to GraphBLAS
+t = tic ;
+[W_gb, bias_gb, Y0_gb] = dnn_mat2gb (W, bias, Y0) ;
+t = toc (t) ;
+fprintf ('setup time: %g sec\n', t) ;
+
# layers:   16
+# neurons:  4096
+# features: 30000
+construct problem time: 3.93937 sec
+setup time: 0.240521 sec
+

Solving the sparse deep neural network problem with GraphbLAS

Please wait ...

tic
+Y1 = GrB.dnn (W_gb, bias_gb, Y0_gb) ;
+gb_time = toc ;
+fprintf ('total time in GraphBLAS: %g sec\n', gb_time) ;
+
total time in GraphBLAS: 7.06691 sec
+

Solving the sparse deep neural network problem with MATLAB

Please wait ...

tic
+Y2 = dnn_matlab (W, bias, Y0) ;
+matlab_time = toc ;
+fprintf ('total time in MATLAB:    %g sec\n', matlab_time) ;
+fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
+    matlab_time / gb_time) ;
+
+err = norm (Y1-Y2,1)
+
total time in MATLAB:    86.8548 sec
+Speedup of GraphBLAS over MATLAB: 12.2904
+err =
+     0
+

For objects, GraphBLAS has better colon notation than MATLAB

The MATLAB notation C = A (start:inc:fini) is very handy, and it works great if A is a MATLAB matrix. But for objects like the GraphBLAS matrix, MATLAB starts by creating the explicit index vector I = start:inc:fini. That's fine if the matrix is modest in size, but GraphBLAS can construct huge matrices. The problem is that 1:n cannot be explicitly constructed when n is huge.

The C API for GraphBLAS can represent the colon notation start:inc:fini in an implicit manner, so it can do the indexing without actually forming the explicit list I = start:inc:fini. But there is no access to this method using the MATLAB notation start:inc:fini.

Thus, to compute C = A (start:inc:fini) for very huge matrices, you need to use use a cell array to represent the colon notation, as { start, inc, fini }, instead of start:inc:fini. See 'help GrB.extract', 'help GrB.assign' for the functional form. For the overloaded syntax C(I,J)=A and C=A(I,J), see 'help GrB/subsasgn' and 'help GrB/subsfref'. The cell array syntax isn't conventional, but it is far faster than the MATLAB colon notation for objects, and takes far less memory when I is huge.

n = 1e14 ;
+H = GrB (n, n) ;            % a huge empty matrix
+I = [1 1e9 1e12 1e14] ;
+M = magic (4)
+H (I,I) = M ;
+J = {1, 1e13} ;            % represents 1:1e13 colon notation
+C1 = H (J, J)              % computes C1 = H (1:e13,1:1e13)
+c = nonzeros (C1) ;
+m = nonzeros (M (1:3, 1:3)) ;
+assert (isequal (c, m)) ;
+
M =
+    16     2     3    13
+     5    11    10     8
+     9     7     6    12
+     4    14    15     1
+
+C1 =
+
+  10000000000000x10000000000000 GraphBLAS double matrix, hypersparse by col:
+  9 nonzeros, 9 entries
+
+    (1,1)    16
+    (1000000000,1)    5
+    (1000000000000,1)    9
+    (1,1000000000)    2
+    (1000000000,1000000000)    11
+    (1000000000000,1000000000)    7
+    (1,1000000000000)    3
+    (1000000000,1000000000000)    10
+    (1000000000000,1000000000000)    6
+
+
try
+    % try to compute the same thing with colon
+    % notation (1:1e13), but this fails:
+    C2 = H (1:1e13, 1:1e13)
+catch me
+    error_expected = me
+end
+
error_expected = 
+  MException with properties:
+
+    identifier: 'MATLAB:array:SizeLimitExceeded'
+       message: 'Requested 10000000000000x1 (74505.8GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive.'
+         cause: {}
+         stack: [4x1 struct]
+    Correction: []
+

Iterative solvers work as-is

Many built-in functions work with GraphBLAS matrices unmodified.

A = sparse (rand (4)) ;
+b = sparse (rand (4,1)) ;
+x = gmres (A,b)
+norm (A*x-b)
+x = gmres (GrB(A), GrB(b))
+norm (A*x-b)
+
gmres converged at iteration 4 to a solution with relative residual 0.
+x =
+    0.9105
+    3.8949
+   -0.5695
+   -1.3867
+ans =
+   8.6711e-16
+gmres converged at iteration 4 to a solution with relative residual 0.
+x =
+    0.9105
+    3.8949
+   -0.5695
+   -1.3867
+ans =
+   7.2802e-16
+

... even in single precision

x = gmres (GrB(A,'single'), GrB(b,'single'))
+norm (A*x-b)
+
gmres converged at iteration 4 to a solution with relative residual 0.
+x =
+    0.9105
+    3.8949
+   -0.5695
+   -1.3867
+ans =
+   8.3369e-08
+

Both of the following uses of minres (A,b) fail to converge because A is not symmetric, as the method requires. Both failures are correctly reported, and both the MATLAB version and the GraphBLAS version return the same incorrect vector x.

x = minres (A, b)
+x = minres (GrB(A), GrB(b))
+
minres stopped at iteration 4 without converging to the desired tolerance 1e-06
+because the maximum number of iterations was reached.
+The iterate returned (number 4) has relative residual 0.21.
+x =
+    0.2489
+    0.2081
+    0.0700
+    0.3928
+minres stopped at iteration 4 without converging to the desired tolerance 1e-06
+because the maximum number of iterations was reached.
+The iterate returned (number 4) has relative residual 0.21.
+
+x =
+
+  4x1 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)    0.248942
+    (2,1)    0.208128
+    (3,1)    0.0699707
+    (4,1)    0.392812
+
+

With a proper symmetric matrix

A = A+A' ;
+x = minres (A, b)
+norm (A*x-b)
+x = minres (GrB(A), GrB(b))
+norm (A*x-b)
+
minres converged at iteration 4 to a solution with relative residual 1.3e-11.
+x =
+ -114.0616
+   -1.4211
+  134.8227
+    2.0694
+ans =
+   1.3650e-11
+minres converged at iteration 4 to a solution with relative residual 1.3e-11.
+
+x =
+
+  4x1 GraphBLAS double matrix, sparse by col:
+  4 nonzeros, 4 entries
+
+    (1,1)    -114.062
+    (2,1)    -1.4211
+    (3,1)    134.823
+    (4,1)    2.0694
+
+ans =
+   1.3650e-11
+

Extreme performance differences between GraphBLAS and MATLAB.

The GraphBLAS operations used so far are perhaps 2x to 50x faster than the corresponding MATLAB operations, depending on how many cores your computer has. To run a demo illustrating a 500x or more speedup versus MATLAB, run this demo:

  gbdemo2

It will illustrate an assignment C(I,J)=A that can take under a second in GraphBLAS but several minutes in MATLAB. To make the comparsion even more dramatic, try:

  gbdemo2 (20000)

assuming you have enough memory.

Sparse logical indexing is much, much faster in GraphBLAS

The mask in GraphBLAS acts much like logical indexing in MATLAB, but it is not quite the same. MATLAB logical indexing takes the form:

     C (M) = A (M)

which computes the same thing as the GraphBLAS statement:

     C = GrB.assign (C, M, A)

The GrB.assign statement computes C(M)=A(M), and it is vastly faster than C(M)=A(M), even if the time to convert the GrB matrix back to a MATLAB sparse matrix is included.

GraphBLAS can also compute C (M) = A (M) using overloaded operators for subsref and subsasgn, but C = GrB.assign (C, M, A) is a bit faster.

Here are both methods in GraphBLAS (both are very fast). Setting up:

clear
+n = 4000 ;
+tic
+C = sprand (n, n, 0.1) ;
+A = 100 * sprand (n, n, 0.1) ;
+M = (C > 0.5) ;
+t_setup = toc ;
+fprintf ('nnz(C): %g, nnz(M): %g, nnz(A): %g\n', ...
+    nnz(C), nnz(M), nnz(A)) ;
+fprintf ('\nsetup time:     %g sec\n', t_setup) ;
+
nnz(C): 1.5226e+06, nnz(M): 761163, nnz(A): 1.52245e+06
+
+setup time:     0.597064 sec
+

First method in GraphBLAS, with GrB.assign

Including the time to convert C1 from a GraphBLAS matrix to a MATLAB sparse matrix:

tic
+C1 = GrB.assign (C, M, A) ;
+C1 = double (C1) ;
+gb_time = toc ;
+fprintf ('\nGraphBLAS time: %g sec for GrB.assign\n', gb_time) ;
+
+GraphBLAS time: 0.018073 sec for GrB.assign
+

Second method in GraphBLAS, with C(M)=A(M)

now using overloaded operators, also include the time to convert back to a MATLAB sparse matrix, for good measure:

A2 = GrB (A) ;
+C2 = GrB (C) ;
+tic
+C2 (M) = A2 (M) ;
+C2 = double (C2) ;
+gb_time2 = toc ;
+fprintf ('\nGraphBLAS time: %g sec for C(M)=A(M)\n', gb_time2) ;
+
+GraphBLAS time: 0.041667 sec for C(M)=A(M)
+

Now with MATLAB matrices, with C(M)=A(M)

Please wait, this will take about 10 minutes or so ...

tic
+C (M) = A (M) ;
+matlab_time = toc ;
+
+fprintf ('\nGraphBLAS time: %g sec (GrB.assign)\n', gb_time) ;
+fprintf ('\nGraphBLAS time: %g sec (overloading)\n', gb_time2) ;
+fprintf ('MATLAB time:    %g sec\n', matlab_time) ;
+fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
+    matlab_time / gb_time2) ;
+
+% GraphBLAS computes the exact same result with both methods:
+assert (isequal (C1, C))
+assert (isequal (C2, C))
+C1 - C
+C2 - C
+
+GraphBLAS time: 0.018073 sec (GrB.assign)
+
+GraphBLAS time: 0.041667 sec (overloading)
+MATLAB time:    601.85 sec
+Speedup of GraphBLAS over MATLAB: 14444.3
+ans =
+   All zero sparse: 4000x4000
+ans =
+   All zero sparse: 4000x4000
+

Limitations and their future solutions

The MATLAB interface for SuiteSparse:GraphBLAS is a work-in-progress. It has some limitations, most of which will be resolved over time.

(1) Nonblocking mode:

GraphBLAS has a 'non-blocking' mode, in which operations can be left pending and completed later. SuiteSparse:GraphBLAS uses the non-blocking mode to speed up a sequence of assignment operations, such as C(I,J)=A. However, in its MATLAB interface, this would require a MATLAB mexFunction to modify its inputs. That breaks the MATLAB API standard, so it cannot be safely done. As a result, using GraphBLAS via its MATLAB interface can be slower than when using its C API.

(2) Integer element-wise operations:

Integer operations in MATLAB saturate, so that uint8(255)+1 is 255. To allow for integer monoids, GraphBLAS uses modular arithmetic instead. This is the only way that C=A*B can be defined for integer semirings. However, saturating integer operators could be added in the future, so that element- wise integer operations on GraphBLAS sparse integer matrices could work just the same as their MATLAB counterparts.

So in the future, you could perhaps write this, for both sparse and dense integer matrices A and B:

     C = GrB.eadd ('+saturate.int8', A, B)

to compute the same thing as C=A+B in MATLAB for its full int8 matrices. Note that MATLAB can do this only for dense integer matrices, since it doesn't support sparse integer matrices.

(3) Faster methods:

Most methods in this MATLAB interface are based on efficient parallel C functions in GraphBLAS itself, and are typically as fast or faster than the equivalent built-in operators and functions in MATLAB.

There are few notable exceptions; these will be addressed in the future. Dense matrices and vectors held as GraphBLAS objects are slower than their MATLAB counterparts. horzcat and vertcat, for [A B] and [A;B] when either A or B are GraphBLAS matrices, are also slow, as illustrated below in the next example.

Other methods that will be faster in the future include bandwidth, istriu, istril, isdiag, reshape, issymmetric, and ishermitian.

Here is an example that illustrates the performance of C = [A B]

clear
+A = sparse (rand (2000)) ;
+B = sparse (rand (2000)) ;
+tic
+C1 = [A B] ;
+matlab_time = toc ;
+
+A = GrB (A) ;
+B = GrB (B) ;
+tic
+C2 = [A B] ;
+gb_time = toc ;
+
+err = norm (C1-C2,1)
+fprintf ('\nMATLAB: %g sec, GraphBLAS: %g sec\n', ...
+    matlab_time, gb_time) ;
+if (gb_time > matlab_time)
+    fprintf ('GraphBLAS is slower by a factor of %g\n', ...
+        gb_time / matlab_time) ;
+end
+
err =
+     0
+
+MATLAB: 0.039475 sec, GraphBLAS: 0.13261 sec
+GraphBLAS is slower by a factor of 3.35934
+

(4) Linear indexing:

If A is an m-by-n 2D MATLAB matrix, with n > 1, A(:) is a column vector of length m*n. The index operation A(i) accesses the ith entry in the vector A(:). This is called linear indexing in MATLAB. It is not yet available for GraphBLAS matrices in this MATLAB interface to GraphBLAS, but will be added in the future.

(5) Implicit singleton dimension expansion

In MATLAB C=A+B where A is m-by-n and B is a 1-by-n row vector implicitly expands B to a matrix, computing C(i,j)=A(i,j)+B(j). This implicit expansion is not yet suported in GraphBLAS with C=A+B. However, it can be done with C = GrB.mxm ('+.+', A, diag(GrB(B))). That's a nice example of the power of semirings, but it's not immediately obvious, and not as clear a syntax as C=A+B. The GraphBLAS/@GrB/dnn.m function uses this 'plus.plus' semiring to apply the bias to each neuron.

A = magic (3)
+B = 1000:1000:3000
+C1 = A + B
+C2 = GrB.mxm ('+.+', A, diag (GrB (B)))
+err = norm (C1-C2,1)
+
A =
+     8     1     6
+     3     5     7
+     4     9     2
+B =
+        1000        2000        3000
+C1 =
+        1008        2001        3006
+        1003        2005        3007
+        1004        2009        3002
+
+C2 =
+
+  3x3 GraphBLAS double matrix, sparse by col:
+  9 nonzeros, 9 entries
+
+    (1,1)    1008
+    (2,1)    1003
+    (3,1)    1004
+    (1,2)    2001
+    (2,2)    2005
+    (3,2)    2009
+    (1,3)    3006
+    (2,3)    3007
+    (3,3)    3002
+
+err =
+     0
+

(6) Performance issues

The GrB matrix is a MATLAB object, and there are some cases where performance issues can arise. Extracting the contents of a MATLAB object (G.field) takes much more time than for a MATLAB struct with the same syntax, and building an object has similar issues. The difference is small, and it does not affect large problems. But if you have many calls to GrB operations with a small amount of work, then the time can be dominated by the MATLAB object-oriented overhead.

A = rand (3,4) ;
+G = GrB (A) ;
+tic
+for k = 1:100000
+    [m, n] = size (A) ;
+end
+toc
+tic
+for k = 1:100000
+    [m, n] = size (G) ;
+end
+toc
+
Elapsed time is 0.036883 seconds.
+Elapsed time is 0.613402 seconds.
+

GraphBLAS operations

In addition to the overloaded operators (such as C=A*B) and overloaded functions (such as L=tril(A)), GraphBLAS also has methods of the form GrB.method. Most of them take an optional input matrix Cin, which is the initial value of the matrix C for the expression below, an optional mask matrix M, and an optional accumulator operator.

    C<#M,replace> = accum (C, T)

In the above expression, #M is either empty (no mask), M (with a mask matrix) or ~M (with a complemented mask matrix), as determined by the descriptor. 'replace' can be used to clear C after it is used in accum(C,T) but before it is assigned with C<...> = Z, where Z=accum(C,T). The matrix T is the result of some operation, such as T=A*B for GrB.mxm, or T=op(A,B) for GrB.eadd.

For a complete list of GraphBLAS overloaded operators and methods, type:

help GrB
+

Thanks for watching!

Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis See also doc sparse and https://twitter.com/DocSparse

\ No newline at end of file diff --git a/GraphBLAS/demo/html/DellXPS13/graphblas_demo2.html b/GraphBLAS/demo/html/DellXPS13/graphblas_demo2.html new file mode 100644 index 0000000000..26a1fca52e --- /dev/null +++ b/GraphBLAS/demo/html/DellXPS13/graphblas_demo2.html @@ -0,0 +1,197 @@ + + + + + graphblas_demo2
% Run the GraphBLAS demo2
+
+% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2020, All Rights Reserved.
+% http://suitesparse.com   See GraphBLAS/Doc/License.txt for license.
+
+gbdemo2
+
 GBDEMO2 Extreme performance differences: GraphBLAS vs MATLAB.
+ 
+  Usage:
+ 
+        gbdemo2             % uses a default bnz = 6000
+        gbdemo2 (20000)     % uses bnz = 20000
+ 
+  The GraphBLAS operations used in gbdemo are perhaps 3x to 50x
+  faster than the corresponding MATLAB operations, depending on how
+  many cores your computer has.  Here's an example where GraphBLAS is
+  asymptotically far faster than MATLAB R2019a: a simple assignment
+  for a large matrix C:
+ 
+        C(I,J) = A
+ 
+  The matrix C is constructed via C = kron (B,B) where nnz (B) is
+  roughly the bnz provided on input (with a default of bnz = 6000),
+  so that C will have about bnz^2 entries, or 36 million by default.
+  I and J are chosen randomly, and A is 5000-by-5000.
+ 
+  When the problem becomes large, MATLAB will take a very long time.
+  If you have enough memory, and want to see higher speedups in
+  GraphBLAS, increase bnz (and be prepared to wait even longer).
+  With the default bnz = 6000, this test takes about 4GB of RAM.
+ 
+  On my Dell XPS 4-core laptop (Intel(R) Core(TM) i7-8565U, 16GB
+  RAM), using MATLAB R2019a, when C becomes 9 million by 9 million,
+  the computation C(I,J)=A for MATLAB matrices C, I, J, and A takes
+  several minutes, whereas GraphBLAS takes less than a second, or
+  about 500x faster than MATLAB.  On a desktop with an Intel(R)
+  Xeon(R) CPU E5-2698 v4 @ 2.20GHz with 20 hardware cores, the
+  speedup over MATLAB is even more dramatic (up to 2,660x has been
+  observed).
+ 
+  See also GrB.assign, subsasgn.
+
+
+# of threads used in GraphBLAS: 8
+
+
+C(I,J)=A where C is 1 million -by- 1 million
+with 35.7126 million entries:
+
+    A is 5000-by-5000 with 49954 entries
+    setup time:     0.261989 sec
+    GraphBLAS time: 0.272427 sec
+    Starting MATLAB ... please wait ... 
+    MATLAB time:    0.349314 sec
+    Speedup of GraphBLAS over MATLAB: 1.28223
+    check time:     0.260897 sec
+    all tests passed
+
+C(I,J)=A where C is 4 million -by- 4 million
+with 35.8202 million entries:
+
+    A is 5000-by-5000 with 49954 entries
+    setup time:     0.319877 sec
+    GraphBLAS time: 0.333537 sec
+    Starting MATLAB ... please wait ... 
+    MATLAB time:    0.345186 sec
+    Speedup of GraphBLAS over MATLAB: 1.03493
+    check time:     0.297323 sec
+    all tests passed
+
+C(I,J)=A where C is 9 million -by- 9 million
+with 35.928 million entries:
+
+    A is 5000-by-5000 with 49954 entries
+    setup time:     0.356083 sec
+    GraphBLAS time: 0.391448 sec
+    Starting MATLAB ... please wait ... 
+    MATLAB time:    187.06 sec
+    Speedup of GraphBLAS over MATLAB: 477.866
+    check time:     0.292156 sec
+    all tests passed
+
+C(I,J)=A where C is 16 million -by- 16 million
+with 35.916 million entries:
+
+    A is 5000-by-5000 with 49954 entries
+    setup time:     0.40299 sec
+    GraphBLAS time: 0.446623 sec
+    Starting MATLAB ... please wait ... 
+    MATLAB time:    199.164 sec
+    Speedup of GraphBLAS over MATLAB: 445.934
+    check time:     0.492775 sec
+    all tests passed
+
+C(I,J)=A where C is 25 million -by- 25 million
+with 35.964 million entries:
+
+    A is 5000-by-5000 with 49954 entries
+    setup time:     0.464605 sec
+    GraphBLAS time: 0.395374 sec
+    Starting MATLAB ... please wait ... 
+    MATLAB time:    230.122 sec
+    Speedup of GraphBLAS over MATLAB: 582.036
+    check time:     0.369713 sec
+    all tests passed
+
+C(I,J)=A where C is 36 million -by- 36 million
+with 35.976 million entries:
+
+    A is 5000-by-5000 with 49954 entries
+    setup time:     0.510898 sec
+    GraphBLAS time: 0.681213 sec
+    Starting MATLAB ... please wait ... 
+    MATLAB time:    251.809 sec
+    Speedup of GraphBLAS over MATLAB: 369.649
+    check time:     0.416664 sec
+    all tests passed
+
\ No newline at end of file diff --git a/GraphBLAS/demo/html/DellXPS13/v310/graphblas_demo.pdf b/GraphBLAS/demo/html/DellXPS13/v310/graphblas_demo.pdf deleted file mode 100644 index f0d0be73e8..0000000000 Binary files a/GraphBLAS/demo/html/DellXPS13/v310/graphblas_demo.pdf and /dev/null differ diff --git a/GraphBLAS/demo/html/DellXPS13/v310/graphblas_demo2.pdf b/GraphBLAS/demo/html/DellXPS13/v310/graphblas_demo2.pdf deleted file mode 100644 index 1573f9c9f1..0000000000 Binary files a/GraphBLAS/demo/html/DellXPS13/v310/graphblas_demo2.pdf and /dev/null differ diff --git a/GraphBLAS/demo/html/DellXPS13/v312/graphblas_demo.html b/GraphBLAS/demo/html/DellXPS13/v312/graphblas_demo.html deleted file mode 100644 index 285834a3aa..0000000000 --- a/GraphBLAS/demo/html/DellXPS13/v312/graphblas_demo.html +++ /dev/null @@ -1,2685 +0,0 @@ - - - - - GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS is a library for creating graph algorithms based on sparse linear algebraic operations over semirings. Visit http://graphblas.org for more details and resources. See also the SuiteSparse:GraphBLAS User Guide in this package.

SuiteSparse:GraphBLAS, (c) 2017-2019, Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis

Contents

GraphBLAS: faster and more general sparse matrices for MATLAB

GraphBLAS is not only useful for creating graph algorithms; it also supports a wide range of sparse matrix data types and operations. MATLAB can compute C=A*B with just two semirings: 'plus.times.double' and 'plus.times.complex' for complex matrices. GraphBLAS has 1,040 unique built-in semirings, such as 'max.plus' (https://en.wikipedia.org/wiki/Tropical_semiring). These semirings can be used to construct a wide variety of graph algorithms, based on operations on sparse adjacency matrices.

GraphBLAS supports sparse double and single precision matrices, logical, and sparse integer matrices: int8, int16, int32, int64, uint8, uint16, uint32, and uint64. Complex matrices will be added in the future.

clear all
-format compact
-rng ('default') ;
-X = 100 * rand (2) ;
-G = GrB (X)              % GraphBLAS copy of a matrix X, same type
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    81.4724
-    (2,1)    90.5792
-    (1,2)    12.6987
-    (2,2)    91.3376
-
-

Sparse integer matrices

Here's an int8 version of the same matrix:

S = int8 (G)            % convert G to a full MATLAB int8 matrix
-G = GrB (X, 'int8')      % a GraphBLAS sparse int8 matrix
-
S =
-  2x2 int8 matrix
-   81   12
-   90   91
-
-G =
-
-  2x2 GraphBLAS int8_t matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)   81
-    (2,1)   90
-    (1,2)   12
-    (2,2)   91
-
-

Sparse single-precision matrices

Matrix operations in GraphBLAS are typically as fast, or faster than MATLAB. Here's an unfair comparison: computing X^2 with MATLAB in double precision and with GraphBLAS in single precision. You would naturally expect GraphBLAS to be faster.

Please wait ...

n = 1e5 ;
-X = spdiags (rand (n, 201), -100:100, n, n) ;
-G = GrB (X, 'single') ;
-tic
-G2 = G^2 ;
-gb_time = toc ;
-tic
-X2 = X^2 ;
-matlab_time = toc ;
-fprintf ('\nGraphBLAS time: %g sec (in single)\n', gb_time) ;
-fprintf ('MATLAB time:    %g sec (in double)\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
-GraphBLAS time: 1.62213 sec (in single)
-MATLAB time:    5.97126 sec (in double)
-Speedup of GraphBLAS over MATLAB: 3.68113
-

Mixing MATLAB and GraphBLAS matrices

The error in the last computation is about eps('single') since GraphBLAS did its computation in single precision, while MATLAB used double precision. MATLAB and GraphBLAS matrices can be easily combined, as in X2-G2. The sparse single precision matrices take less memory space.

err = norm (X2 - G2, 1) / norm (X2,1)
-eps ('single')
-whos G G2 X X2
-
err =
-   1.5049e-07
-ans =
-  single
-  1.1921e-07
-  Name           Size                    Bytes  Class     Attributes
-
-  G         100000x100000            241879772  GrB                 
-  G2        100000x100000            481518572  GrB                 
-  X         100000x100000            322238408  double    sparse    
-  X2        100000x100000            641756808  double    sparse    
-
-

Faster matrix operations

But even with standard double precision sparse matrices, GraphBLAS is typically faster than the built-in MATLAB methods. Here's a fair comparison:

G = GrB (X) ;
-tic
-G2 = G^2 ;
-gb_time = toc ;
-err = norm (X2 - G2, 1) / norm (X2,1)
-fprintf ('\nGraphBLAS time: %g sec (in double)\n', gb_time) ;
-fprintf ('MATLAB time:    %g sec (in double)\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
err =
-     0
-
-GraphBLAS time: 1.7605 sec (in double)
-MATLAB time:    5.97126 sec (in double)
-Speedup of GraphBLAS over MATLAB: 3.39181
-

A wide range of semirings

MATLAB can only compute C=A*B using the standard '+.*.double' and '+.*.complex' semirings. A semiring is defined in terms of a string, 'add.mult.type', where 'add' is a monoid that takes the place of the additive operator, 'mult' is the multiplicative operator, and 'type' is the data type for the two inputs to the mult operator (the type defaults to the type of A for C=A*B).

In the standard semiring, C=A*B is defined as:

C(i,j) = sum (A(i,:).' .* B(:,j))
-

using 'plus' as the monoid and 'times' as the multiplicative operator. But in a more general semiring, 'sum' can be any monoid, which is an associative and commutative operator that has an identity value. For example, in the 'max.plus' tropical algebra, C(i,j) for C=A*B is defined as:

C(i,j) = max (A(i,:).' + B(:,j))
-

This can be computed in GraphBLAS with:

C = GrB.mxm ('max.+', A, B)
-
n = 3 ;
-A = rand (n) ;
-B = rand (n) ;
-C = zeros (n) ;
-for i = 1:n
-    for j = 1:n
-        C(i,j) = max (A (i,:).' + B (:,j)) ;
-    end
-end
-C2 = GrB.mxm ('max.+', A, B) ;
-fprintf ('\nerr = norm (C-C2,1) = %g\n', norm (C-C2,1)) ;
-
-err = norm (C-C2,1) = 0
-

The max.plus tropical semiring

Here are details of the "max.plus" tropical semiring. The identity value is -inf since max(x,-inf) = max (-inf,x) = -inf for any x.

GrB.semiringinfo ('max.+.double') ;
-
-    GraphBLAS Semiring: max.+.double (built-in)
-    GraphBLAS Monoid: semiring->add (built-in)
-    GraphBLAS BinaryOp: monoid->op (built-in) z=max(x,y)
-    GraphBLAS type: ztype double size: 8
-    GraphBLAS type: xtype double size: 8
-    GraphBLAS type: ytype double size: 8
-    identity: [    -inf ] terminal: [    inf ]
-
-    GraphBLAS BinaryOp: semiring->multiply (built-in) z=plus(x,y)
-    GraphBLAS type: ztype double size: 8
-    GraphBLAS type: xtype double size: 8
-    GraphBLAS type: ytype double size: 8
-

A boolean semiring

MATLAB cannot multiply two logical matrices. MATLAB R2019a converts them to double and uses the conventional +.*.double semiring instead. In GraphBLAS, this is the common Boolean 'or.and.logical' semiring, which is widely used in linear algebraic graph algorithms.

GrB.semiringinfo ('|.&.logical') ;
-
-    GraphBLAS Semiring: |.&.logical (built-in)
-    GraphBLAS Monoid: semiring->add (built-in)
-    GraphBLAS BinaryOp: monoid->op (built-in) z=or(x,y)
-    GraphBLAS type: ztype bool size: 1
-    GraphBLAS type: xtype bool size: 1
-    GraphBLAS type: ytype bool size: 1
-    identity: [   0 ] terminal: [   1 ]
-
-    GraphBLAS BinaryOp: semiring->multiply (built-in) z=and(x,y)
-    GraphBLAS type: ztype bool size: 1
-    GraphBLAS type: xtype bool size: 1
-    GraphBLAS type: ytype bool size: 1
-
clear
-A = sparse (rand (3) > 0.5)
-B = sparse (rand (3) > 0.2)
-
A =
-  3x3 sparse logical array
-   (2,1)      1
-   (2,2)      1
-   (3,2)      1
-   (1,3)      1
-B =
-  3x3 sparse logical array
-   (1,1)      1
-   (2,1)      1
-   (3,1)      1
-   (1,2)      1
-   (2,2)      1
-   (3,2)      1
-   (1,3)      1
-   (2,3)      1
-   (3,3)      1
-
try
-    % MATLAB R2019a does this by casting A and B to double
-    C1 = A*B
-catch
-    % MATLAB R2018a throws an error
-    fprintf ('MATLAB R2019a required for C=A*B with logical\n') ;
-    fprintf ('matrices.  Explicitly converting to double:\n') ;
-    C1 = double (A) * double (B)
-end
-C2 = GrB (A) * GrB (B)
-
C1 =
-   (1,1)        1
-   (2,1)        2
-   (3,1)        1
-   (1,2)        1
-   (2,2)        2
-   (3,2)        1
-   (1,3)        1
-   (2,3)        2
-   (3,3)        1
-
-C2 =
-
-  3x3 GraphBLAS bool matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)   1
-    (2,1)   1
-    (3,1)   1
-    (1,2)   1
-    (2,2)   1
-    (3,2)   1
-    (1,3)   1
-    (2,3)   1
-    (3,3)   1
-
-

Note that C1 is a MATLAB sparse double matrix, and contains non-binary values. C2 is a GraphBLAS logical matrix.

whos
-GrB.type (C2)
-
  Name      Size            Bytes  Class      Attributes
-
-  A         3x3                68  logical    sparse    
-  B         3x3               113  logical    sparse    
-  C1        3x3               176  double     sparse    
-  C2        3x3              1079  GrB                  
-
-ans =
-    'logical'
-

GraphBLAS operators, monoids, and semirings

The C interface for SuiteSparse:GraphBLAS allows for arbitrary types and operators to be constructed. However, the MATLAB interface to SuiteSparse:GraphBLAS is restricted to pre-defined types and operators: a mere 11 types, 66 unary operators, 275 binary operators, 44 monoids, 16 select operators, and 1,865 semirings (1,040 of which are unique, since some binary operators are equivalent: 'min.logical' and '&.logical' are the same thing, for example). The complex type and its binary operators, monoids, and semirings will be added in the near future.

That gives you a lot of tools to create all kinds of interesting graph algorithms. For example:

GrB.bfs    % breadth-first search
-GrB.dnn    % sparse deep neural network (http://graphchallenge.org)
-GrB.mis    % maximal independent set
-

See 'help GrB.binopinfo' for a list of the binary operators, and 'help GrB.monoidinfo' for the ones that can be used as the additive monoid in a semiring.

help GrB.binopinfo
-
 GRB.BINOPINFO list the details of a GraphBLAS binary operator.
- 
-  Usage
- 
-    GrB.binopinfo
-    GrB.binopinfo (op)
-    GrB.binopinfo (op, type)
- 
-  For GrB.binopinfo(op), the op must be a string of the form
-  'op.type', where 'op' is listed below.  The second usage allows the
-  type to be omitted from the first argument, as just 'op'.  This is
-  valid for all GraphBLAS operations, since the type defaults to the
-  type of the input matrices.  However, GrB.binopinfo does not have a
-  default type and thus one must be provided, either in the op as
-  GrB.binopinfo ('+.double'), or in the second argument, GrB.binopinfo
-  ('+', 'double').
- 
-  The MATLAB interface to GraphBLAS provides for 25 different binary
-  operators, each of which may be used with any of the 11 types, for
-  a total of 25*11 = 275 valid binary operators.  Binary operators
-  are defined by a string of the form 'op.type', or just 'op'.  In
-  the latter case, the type defaults to the type of the matrix inputs
-  to the GraphBLAS operation.
- 
-  The 6 comparator operators come in two flavors.  For the is*
-  operators, the result has the same type as the inputs, x and y,
-  with 1 for true and 0 for false.  For example isgt.double (pi, 3.0)
-  is the double value 1.0.  For the second set of 6 operators (eq,
-  ne, gt, lt, ge, le), the result is always logical (true or false).
-  In a semiring, the type of the add monoid must exactly match the
-  type of the output of the multiply operator, and thus
-  'plus.iseq.double' is valid (counting how many terms are equal).
-  The 'plus.eq.double' semiring is valid, but not the same semiring
-  since the 'plus' of 'plus.eq.double' has a logical type and is thus
-  equivalent to 'or.eq.double'.   The 'or.eq' is true if any terms
-  are equal and false otherwise (it does not count the number of
-  terms that are equal).
- 
-  The following binary operators are available.  Many have equivalent
-  synonyms, so that '1st' and 'first' both define the first(x,y) = x
-  operator.
- 
-    operator name(s) f(x,y)         |   operator names(s) f(x,y)
-    ---------------- ------         |   ----------------- ------
-    1st first        x              |   iseq             x == y
-    2nd second       y              |   isne             x ~= y
-    min              min(x,y)       |   isgt             x > y
-    max              max(x,y)       |   islt             x < y
-    +   plus         x+y            |   isge             x >= y
-    -   minus        x-y            |   isle             x <= y
-    rminus           y-x            |   ==  eq           x == y
-    *   times        x*y            |   ~=  ne           x ~= y
-    /   div          x/y            |   >   gt           x > y
-    \   rdiv         y/x            |   <   lt           x < y
-    |   || or  lor   x | y          |   >=  ge           x >= y
-    &   && and land  x & y          |   <=  le           x <= y
-    xor lxor         xor(x,y)       |
- 
-  The three logical operators, lor, land, and lxor, also come in 11
-  types.  z = lor.double (x,y) tests the condition (x~=0) || (y~=0),
-  and returns the double value 1.0 if true, or 0.0 if false.
- 
-  Example:
- 
-    % valid binary operators
-    GrB.binopinfo ('+.double') ;
-    GrB.binopinfo ('1st.int32') ;
- 
-    % invalid binary operator (an error; this is a unary op):
-    GrB.binopinfo ('abs.double') ;
- 
-  See also GrB.descriptorinfo, GrB.monoidinfo, GrB.selectopinfo,
-  GrB.semiringinfo, GrB.unopinfo.
-
-
help GrB.monoidinfo
-
 GRB.MONOIDINFO list the details of a GraphBLAS monoid.
- 
-  Usage
- 
-    GrB.monoidinfo
-    GrB.monoidinfo (monoid)
-    GrB.monoidinfo (monoid, type)
- 
-  For GrB.monoidinfo(op), the op must be a string of the form
-  'op.type', where 'op' is listed below.  The second usage allows the
-  type to be omitted from the first argument, as just 'op'.  This is
-  valid for all GraphBLAS operations, since the type defaults to the
-  type of the input matrices.  However, GrB.monoidinfo does not have a
-  default type and thus one must be provided, either in the op as
-  GrB.monoidinfo ('+.double'), or in the second argument,
-  GrB.monoidinfo ('+', 'double').
- 
-  The MATLAB interface to GraphBLAS provides for 44 different
-  monoids.  The valid monoids are: '+', '*', 'max', and 'min' for all
-  but the 'logical' type, and '|', '&', 'xor', and 'eq' for the
-  'logical' type.
- 
-  Example:
- 
-    % valid monoids
-    GrB.monoidinfo ('+.double') ;
-    GrB.monoidinfo ('*.int32') ;
- 
-    % invalid monoids
-    GrB.monoidinfo ('1st.int32') ;
-    GrB.monoidinfo ('abs.double') ;
- 
-  See also GrB.binopinfo, GrB.descriptorinfo, % GrB.selectopinfo,
-  GrB.semiringinfo, GrB.unopinfo.
-
-

Element-wise operations

Binary operators can be used in element-wise matrix operations, like C=A+B and C=A.*B. For the matrix addition C=A+B, the pattern of C is the set union of A and B, and the '+' operator is applied for entries in the intersection. Entries in A but not B, or in B but not A, are assigned to C without using the operator. The '+' operator is used for C=A+B but any operator can be used with GrB.eadd.

A = GrB (sprand (3, 3, 0.5)) ;
-B = GrB (sprand (3, 3, 0.5)) ;
-C1 = A + B
-C2 = GrB.eadd ('+', A, B)
-err = norm (C1-C2,1)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    1.47841
-    (2,2)    0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    1.47841
-    (2,2)    0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-err =
-     0
-

Subtracting two matrices

A-B and GrB.eadd ('-', A, B) are not the same thing, since the '-' operator is not applied to an entry that is in B but not A.

C1 = A-B
-C2 = GrB.eadd ('-', A, B)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    -0.666139
-    (3,1)    -0.735859
-    (1,2)    -0.334348
-    (2,2)    -0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    -0.334348
-    (2,2)    0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-

But these give the same result

C1 = A-B
-C2 = GrB.eadd ('+', A, GrB.apply ('-', B))
-err = norm (C1-C2,1)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    -0.666139
-    (3,1)    -0.735859
-    (1,2)    -0.334348
-    (2,2)    -0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    -0.666139
-    (3,1)    -0.735859
-    (1,2)    -0.334348
-    (2,2)    -0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-err =
-     0
-

Element-wise 'multiplication'

For C = A.*B, the result C is the set intersection of the pattern of A and B. The operator is applied to entries in both A and B. Entries in A but not B, or B but not A, do not appear in the result C.

C1 = A.*B
-C2 = GrB.emult ('*', A, B)
-C3 = double (A) .* double (B)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  1 nonzero, 1 entry
-
-    (1,2)    0.518474
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  1 nonzero, 1 entry
-
-    (1,2)    0.518474
-
-C3 =
-   (1,2)       0.5185
-

Just as in GrB.eadd, any operator can be used in GrB.emult:

A
-B
-C2 = GrB.emult ('max', A, B)
-
-A =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,2)    0.572029
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-B =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    0.906378
-    (2,2)    0.146938
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  1 nonzero, 1 entry
-
-    (1,2)    0.906378
-
-

Overloaded operators

The following operators all work as you would expect for any matrix. The matrices A and B can be GraphBLAS matrices, or MATLAB sparse or dense matrices, in any combination, or scalars where appropriate:

  A+B   A-B  A*B   A.*B  A./B  A.\B  A.^b   A/b   C=A(I,J)
-  -A    +A   ~A    A'    A.'   A&B   A|B    b\A   C(I,J)=A
-  A~=B  A>B  A==B  A<=B  A>=B  A<B   [A,B]  [A;B]
-  A(1:end,1:end)

For A^b, b must be a non-negative integer.

C1 = [A B] ;
-C2 = [double(A) double(B)] ;
-assert (isequal (double (C1), C2))
-
C1 = A^2
-C2 = double (A)^2 ;
-err = norm (C1 - C2, 1)
-assert (err < 1e-12)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  5 nonzeros, 5 entries
-
-    (2,2)    0.140946
-    (3,2)    0.0590838
-    (1,3)    0.142227
-    (2,3)    0.0259144
-    (3,3)    0.151809
-
-err =
-     0
-
C1 = A (1:2,2:end)
-A = double (A) ;
-C2 = A (1:2,2:end) ;
-assert (isequal (double (C1), C2))
-
-C1 =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  2 nonzeros, 2 entries
-
-    (1,1)    0.572029
-    (2,2)    0.248635
-
-

Overloaded functions

Many MATLAB built-in functions can be used with GraphBLAS matrices:

A few differences with the built-in functions:

S = sparse (G)        % makes a copy of a GrB matrix
-F = full (G)          % adds explicit zeros, so numel(F)==nnz(F)
-F = full (G,type,id)  % adds explicit identity values to a GrB matrix
-disp (G, level)       % display a GrB matrix G; level=2 is the default.
-

In the list below, the first set of Methods are overloaded built-in methods. They are used as-is on GraphBLAS matrices, such as C=abs(G). The Static methods are prefixed with "GrB.", as in C = GrB.apply ( ... ).

methods GrB
-
-Methods for class GrB:
-
-GrB             ge              le              sparse          
-abs             graph           length          spfun           
-all             gt              logical         spones          
-amd             horzcat         lt              sprand          
-and             int16           max             sprandn         
-any             int32           min             sprandsym       
-assert          int64           minus           sprintf         
-bandwidth       int8            mldivide        sqrt            
-ceil            isa             mpower          subsasgn        
-colamd          isbanded        mrdivide        subsref         
-complex         isdiag          mtimes          sum             
-conj            isempty         ne              symamd          
-ctranspose      isequal         nnz             symrcm          
-diag            isfinite        nonzeros        times           
-digraph         isfloat         norm            transpose       
-disp            ishermitian     not             tril            
-display         isinf           numel           triu            
-dmperm          isinteger       nzmax           true            
-double          islogical       ones            uint16          
-eig             ismatrix        or              uint32          
-end             isnan           plus            uint64          
-eps             isnumeric       power           uint8           
-eq              isreal          prod            uminus          
-etree           isscalar        rdivide         uplus           
-false           issparse        real            vertcat         
-find            issymmetric     repmat          xor             
-fix             istril          reshape         zeros           
-flip            istriu          round           
-floor           isvector        sign            
-fprintf         kron            single          
-full            ldivide         size            
-
-Static methods:
-
-apply           emult           kronecker       select          
-assign          entries         ktruss          selectopinfo    
-bfs             expand          laplacian       semiringinfo    
-binopinfo       extract         mis             speye           
-build           extracttuples   monoidinfo      subassign       
-chunk           eye             mxm             threads         
-clear           format          nonz            trans           
-compact         incidence       offdiag         tricount        
-descriptorinfo  isbycol         pagerank        type            
-dnn             isbyrow         prune           unopinfo        
-eadd            isfull          random          vreduce         
-empty           issigned        reduce          
-
-

Zeros are handled differently

Explicit zeros cannot be automatically dropped from a GraphBLAS matrix, like they are in MATLAB sparse matrices. In a shortest-path problem, for example, an edge A(i,j) that is missing has an infinite weight, (the monoid identity of min(x,y) is +inf). A zero edge weight A(i,j)=0 is very different from an entry that is not present in A. However, if a GraphBLAS matrix is converted into a MATLAB sparse matrix, explicit zeros are dropped, which is the convention for a MATLAB sparse matrix. They can also be dropped from a GraphBLAS matrix using the GrB.select method.

G = GrB (magic (2)) ;
-G (1,1) = 0      % G(1,1) still appears as an explicit entry
-A = double (G)   % but it's dropped when converted to MATLAB sparse
-H = GrB.select ('nonzero', G)  % drops the explicit zeros from G
-fprintf ('nnz (G): %d  nnz (A): %g nnz (H): %g\n', ...
-    nnz (G), nnz (A), nnz (H)) ;
-fprintf ('num entries in G: %d\n', GrB.entries (G)) ;
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  3 nonzeros, 4 entries
-
-    (1,1)    0
-    (2,1)    4
-    (1,2)    3
-    (2,2)    2
-
-A =
-   (2,1)        4
-   (1,2)        3
-   (2,2)        2
-
-H =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  3 nonzeros, 3 entries
-
-    (2,1)    4
-    (1,2)    3
-    (2,2)    2
-
-nnz (G): 3  nnz (A): 3 nnz (H): 3
-num entries in G: 4
-

Displaying contents of a GraphBLAS matrix

Unlike MATLAB, the default is to display just a few entries of a GrB matrix. Here are all 100 entries of a 10-by-10 matrix, using a non-default disp(G,3):

G = GrB (rand (10)) ;
-% display everything:
-disp (G,3)
-
-G =
-
-  10x10 GraphBLAS double matrix, sparse by col:
-  100 nonzeros, 100 entries
-
-    (1,1)    0.0342763
-    (2,1)    0.17802
-    (3,1)    0.887592
-    (4,1)    0.889828
-    (5,1)    0.769149
-    (6,1)    0.00497062
-    (7,1)    0.735693
-    (8,1)    0.488349
-    (9,1)    0.332817
-    (10,1)    0.0273313
-    (1,2)    0.467212
-    (2,2)    0.796714
-    (3,2)    0.849463
-    (4,2)    0.965361
-    (5,2)    0.902248
-    (6,2)    0.0363252
-    (7,2)    0.708068
-    (8,2)    0.322919
-    (9,2)    0.700716
-    (10,2)    0.472957
-    (1,3)    0.204363
-    (2,3)    0.00931977
-    (3,3)    0.565881
-    (4,3)    0.183435
-    (5,3)    0.00843818
-    (6,3)    0.284938
-    (7,3)    0.706156
-    (8,3)    0.909475
-    (9,3)    0.84868
-    (10,3)    0.564605
-    (1,4)    0.075183
-    (2,4)    0.535293
-    (3,4)    0.072324
-    (4,4)    0.515373
-    (5,4)    0.926149
-    (6,4)    0.949252
-    (7,4)    0.0478888
-    (8,4)    0.523767
-    (9,4)    0.167203
-    (10,4)    0.28341
-    (1,5)    0.122669
-    (2,5)    0.441267
-    (3,5)    0.157113
-    (4,5)    0.302479
-    (5,5)    0.758486
-    (6,5)    0.910563
-    (7,5)    0.0246916
-    (8,5)    0.232421
-    (9,5)    0.38018
-    (10,5)    0.677531
-    (1,6)    0.869074
-    (2,6)    0.471459
-    (3,6)    0.624929
-    (4,6)    0.987186
-    (5,6)    0.282885
-    (6,6)    0.843833
-    (7,6)    0.869597
-    (8,6)    0.308209
-    (9,6)    0.201332
-    (10,6)    0.706603
-    (1,7)    0.563222
-    (2,7)    0.575795
-    (3,7)    0.056376
-    (4,7)    0.73412
-    (5,7)    0.608022
-    (6,7)    0.0400164
-    (7,7)    0.540801
-    (8,7)    0.023064
-    (9,7)    0.165682
-    (10,7)    0.250393
-    (1,8)    0.23865
-    (2,8)    0.232033
-    (3,8)    0.303191
-    (4,8)    0.579934
-    (5,8)    0.267751
-    (6,8)    0.916376
-    (7,8)    0.833499
-    (8,8)    0.978692
-    (9,8)    0.734445
-    (10,8)    0.102896
-    (1,9)    0.353059
-    (2,9)    0.738955
-    (3,9)    0.57539
-    (4,9)    0.751433
-    (5,9)    0.93256
-    (6,9)    0.281622
-    (7,9)    0.51302
-    (8,9)    0.24406
-    (9,9)    0.950086
-    (10,9)    0.303638
-    (1,10)    0.563593
-    (2,10)    0.705101
-    (3,10)    0.0604146
-    (4,10)    0.672065
-    (5,10)    0.359793
-    (6,10)    0.62931
-    (7,10)    0.977758
-    (8,10)    0.394328
-    (9,10)    0.765651
-    (10,10)    0.457809
-
-
-

That was disp(G,3), so every entry was printed. It's a little long, so the default is not to print everything.

With the default display (level = 2):

G
-
-G =
-
-  10x10 GraphBLAS double matrix, sparse by col:
-  100 nonzeros, 100 entries
-
-    (1,1)    0.0342763
-    (2,1)    0.17802
-    (3,1)    0.887592
-    (4,1)    0.889828
-    (5,1)    0.769149
-    (6,1)    0.00497062
-    (7,1)    0.735693
-    (8,1)    0.488349
-    (9,1)    0.332817
-    (10,1)    0.0273313
-    (1,2)    0.467212
-    (2,2)    0.796714
-    (3,2)    0.849463
-    (4,2)    0.965361
-    (5,2)    0.902248
-    (6,2)    0.0363252
-    (7,2)    0.708068
-    (8,2)    0.322919
-    (9,2)    0.700716
-    (10,2)    0.472957
-    (1,3)    0.204363
-    (2,3)    0.00931977
-    (3,3)    0.565881
-    (4,3)    0.183435
-    (5,3)    0.00843818
-    (6,3)    0.284938
-    (7,3)    0.706156
-    (8,3)    0.909475
-    (9,3)    0.84868
-    (10,3)    0.564605
-    ...
-
-

That was disp(G,2) or just display(G), which is what is printed by a MATLAB statement that doesn't have a trailing semicolon. With level = 1, disp(G,1) gives just a terse summary:

disp (G,1)
-
-G =
-
-  10x10 GraphBLAS double matrix, sparse by col:
-  100 nonzeros, 100 entries
-
-
-

Storing a matrix by row or by column

MATLAB stores its sparse matrices by column, refered to as 'standard CSC' in SuiteSparse:GraphBLAS. In the CSC (compressed sparse column) format, each column of the matrix is stored as a list of entries, with their value and row index. In the CSR (compressed sparse row) format, each row is stored as a list of values and their column indices. GraphBLAS uses both CSC and CSR, and the two formats can be intermixed arbitrarily. In its C interface, the default format is CSR. However, for better compatibility with MATLAB, this MATLAB interface for SuiteSparse:GraphBLAS uses CSC by default instead.

rng ('default') ;
-GrB.clear ;                      % clear all prior GraphBLAS settings
-fprintf ('the default format is: %s\n', GrB.format) ;
-C = sparse (rand (2))
-G = GrB (C)
-GrB.format (G)
-
the default format is: by col
-C =
-   (1,1)       0.8147
-   (2,1)       0.9058
-   (1,2)       0.1270
-   (2,2)       0.9134
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.814724
-    (2,1)    0.905792
-    (1,2)    0.126987
-    (2,2)    0.913376
-
-ans =
-    'by col'
-

Many graph algorithms work better in CSR format, with matrices stored by row. For example, it is common to use A(i,j) for the edge (i,j), and many graph algorithms need to access the out-adjacencies of nodes, which is the row A(i,;) for node i. If the CSR format is desired, GrB.format ('by row') tells GraphBLAS to create all subsequent matrices in the CSR format. Converting from a MATLAB sparse matrix (in standard CSC format) takes a little more time (requiring a transpose), but subsequent graph algorithms can be faster.

G = GrB (C, 'by row')
-fprintf ('the format of G is:    %s\n', GrB.format (G)) ;
-H = GrB (C)
-fprintf ('the format of H is:    %s\n', GrB.format (H)) ;
-err = norm (H-G,1)
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by row:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.814724
-    (1,2)    0.126987
-    (2,1)    0.905792
-    (2,2)    0.913376
-
-the format of G is:    by row
-
-H =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.814724
-    (2,1)    0.905792
-    (1,2)    0.126987
-    (2,2)    0.913376
-
-the format of H is:    by col
-err =
-     0
-

Hypersparse matrices

SuiteSparse:GraphBLAS can use two kinds of sparse matrix data structures: standard and hypersparse, for both CSC and CSR formats. In the standard CSC format used in MATLAB, an m-by-n matrix A takes O(n+nnz(A)) space. MATLAB can create huge column vectors, but not huge matrices (when n is huge).

clear all
-[c, huge] = computer ;
-C = sparse (huge, 1)    % MATLAB can create a huge-by-1 sparse column
-try
-    C = sparse (huge, huge)     % but this fails
-catch me
-    error_expected = me
-end
-
C =
-   All zero sparse: 281474976710655x1
-error_expected = 
-  MException with properties:
-
-    identifier: 'MATLAB:array:SizeLimitExceeded'
-       message: 'Requested 281474976710655x281474976710655 (2097152.0GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See <a href="matlab: helpview([docroot '/matlab/helptargets.map'], 'matlab_env_workspace_prefs')">array size limit</a> or preference panel for more information.'
-         cause: {}
-         stack: [4x1 struct]
-    Correction: []
-

In a GraphBLAS hypersparse matrix, an m-by-n matrix A takes only O(nnz(A)) space. The difference can be huge if nnz (A) << n.

clear
-[c, huge] = computer ;
-G = GrB (huge, 1)            % no problem for GraphBLAS
-H = GrB (huge, huge)         % this works in GraphBLAS too
-
-G =
-
-  281474976710655x1 GraphBLAS double matrix, sparse by col:
-  no nonzeros, no entries
-
-
-H =
-
-  281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
-  no nonzeros, no entries
-
-

Operations on huge hypersparse matrices are very fast; no component of the time or space complexity is Omega(n).

I = randperm (huge, 2) ;
-J = randperm (huge, 2) ;
-H (I,J) = magic (2) ;        % add 4 nonzeros to random locations in H
-H (I,I) = 10 * [1 2 ; 3 4] ; % so H^2 is not all zero
-H = H^2 ;                    % square H
-H = (H' * 2) ;               % transpose H and double the entries
-K = pi * spones (H) ;
-H = H + K                    % add pi to each entry in H
-
-H =
-
-  281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
-  8 nonzeros, 8 entries
-
-    (27455183225557,27455183225557)    4403.14
-    (78390279669562,27455183225557)    383.142
-    (153933462881710,27455183225557)    343.142
-    (177993304104065,27455183225557)    3003.14
-    (27455183225557,177993304104065)    2003.14
-    (78390279669562,177993304104065)    183.142
-    (153933462881710,177993304104065)    143.142
-    (177993304104065,177993304104065)    1403.14
-
-

numel uses vpa if the matrix is really huge

e1 = numel (G)               % this is huge, but still a flint
-e2 = numel (H)               % this is huge^2, which needs vpa
-whos e1 e2
-
e1 =
-   2.8147e+14
-e2 =
-79228162514263774643590529025.0
-  Name      Size            Bytes  Class     Attributes
-
-  e1        1x1                 8  double              
-  e2        1x1                 8  sym                 
-
-

All of these matrices take very little memory space:

whos C G H K
-
  Name                    Size                         Bytes  Class    Attributes
-
-  G         281474976710655x1                            989  GrB                
-  H         281474976710655x281474976710655             1308  GrB                
-  K         281474976710655x281474976710655             1308  GrB                
-
-

The mask and accumulator

When not used in overloaded operators or built-in functions, many GraphBLAS methods of the form GrB.method ( ... ) can optionally use a mask and/or an accumulator operator. If the accumulator is '+' in GrB.mxm, for example, then C = C + A*B is computed. The mask acts much like logical indexing in MATLAB. With a logical mask matrix M, C<M>=A*B allows only part of C to be assigned. If M(i,j) is true, then C(i,j) can be modified. If false, then C(i,j) is not modified.

For example, to set all values in C that are greater than 0.5 to 3:

A = rand (3)
-C = GrB.assign (A, A > 0.5, 3) ;     % in GraphBLAS
-C1 = GrB (A) ; C1 (A > .5) = 3       % also in GraphBLAS
-C2 = A      ; C2 (A > .5) = 3       % in MATLAB
-err = norm (C - C1, 1)
-err = norm (C - C2, 1)
-
A =
-    0.9575    0.9706    0.8003
-    0.9649    0.9572    0.1419
-    0.1576    0.4854    0.4218
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)    3
-    (2,1)    3
-    (3,1)    0.157613
-    (1,2)    3
-    (2,2)    3
-    (3,2)    0.485376
-    (1,3)    3
-    (2,3)    0.141886
-    (3,3)    0.421761
-
-C2 =
-    3.0000    3.0000    3.0000
-    3.0000    3.0000    0.1419
-    0.1576    0.4854    0.4218
-err =
-     0
-err =
-     0
-

The descriptor

Most GraphBLAS functions of the form GrB.method ( ... ) take an optional last argument, called the descriptor. It is a MATLAB struct that can modify the computations performed by the method. 'help GrB.descriptorinfo' gives all the details. The following is a short summary of the primary settings:

d.out = 'default' or 'replace', clears C after the accum op is used.

d.mask = 'default' or 'complement', to use M or ~M as the mask matrix.

d.in0 = 'default' or 'transpose', to transpose A for C=A*B, C=A+B, etc.

d.in1 = 'default' or 'transpose', to transpose B for C=A*B, C=A+B, etc.

d.kind = 'default', 'GrB', 'sparse', or 'full'; the output of GrB.method.

A = sparse (rand (2)) ;
-B = sparse (rand (2)) ;
-C1 = A'*B ;
-C2 = GrB.mxm ('+.*', A, B, struct ('in0', 'transpose')) ;
-err = norm (C1-C2,1)
-
err =
-     0
-

Integer arithmetic is different in GraphBLAS

MATLAB supports integer arithmetic on its full matrices, using int8, int16, int32, int64, uint8, uint16, uint32, or uint64 data types. None of these integer data types can be used to construct a MATLAB sparse matrix, which can only be double, double complex, or logical. Furthermore, C=A*B is not defined for integer types in MATLAB, except when A and/or B are scalars.

GraphBLAS supports all of those types for its sparse matrices (except for complex, which will be added in the future). All operations are supported, including C=A*B when A or B are any integer type, for all 1,865 semirings (1,040 of which are unique).

However, integer arithmetic differs in GraphBLAS and MATLAB. In MATLAB, integer values saturate if they exceed their maximum value. In GraphBLAS, integer operators act in a modular fashion. The latter is essential when computing C=A*B over a semiring. A saturating integer operator cannot be used as a monoid since it is not associative.

The C API for GraphBLAS allows for the creation of arbitrary user-defined types, so it would be possible to create different binary operators to allow element-wise integer operations to saturate, perhaps:

C = GrB.eadd('+saturate',A,B)
-

This would require an extension to this MATLAB interface.

C = uint8 (magic (3)) ;
-G = GrB (C) ;
-C1 = C * 40
-C2 = G * 40
-C3 = double (G) * 40 ;
-S = double (C1 < 255) ;
-assert (isequal (double (C1).*S, double (C2).*S))
-assert (isequal (nonzeros (C2), double (mod (nonzeros (C3), 256))))
-
C1 =
-  3x3 uint8 matrix
-   255    40   240
-   120   200   255
-   160   255    80
-
-C2 =
-
-  3x3 GraphBLAS uint8_t matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)   64
-    (2,1)   120
-    (3,1)   160
-    (1,2)   40
-    (2,2)   200
-    (3,2)   104
-    (1,3)   240
-    (2,3)   24
-    (3,3)   80
-
-

An example graph algorithm: breadth-first search

The breadth-first search of a graph finds all nodes reachable from the source node, and their level, v. v=GrB.bfs(A,s) or v=bfs_matlab(A,s) compute the same thing, but GrB.bfs uses GraphBLAS matrices and operations, while bfs_matlab uses pure MATLAB operations. v is defined as v(s) = 1 for the source node, v(i) = 2 for nodes adjacent to the source, and so on.

clear all
-rng ('default') ;
-n = 1e5 ;
-A = logical (sprandn (n, n, 1e-3)) ;
-
-tic
-v1 = GrB.bfs (A, 1) ;
-gb_time = toc ;
-
-tic
-v2 = bfs_matlab (A, 1) ;
-matlab_time = toc ;
-
-assert (isequal (double (v1'), v2))
-fprintf ('\nnodes reached: %d of %d\n', nnz (v2), n) ;
-fprintf ('GraphBLAS time: %g sec\n', gb_time) ;
-fprintf ('MATLAB time:    %g sec\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
-nodes reached: 100000 of 100000
-GraphBLAS time: 0.675143 sec
-MATLAB time:    0.458863 sec
-Speedup of GraphBLAS over MATLAB: 0.679653
-

Example graph algorithm: Luby's method in GraphBLAS

The GrB.mis.m function is variant of Luby's randomized algorithm [Luby 1985]. It is a parallel method for finding an maximal independent set of nodes, where no two nodes are adjacent. See the GraphBLAS/@GrB/GrB.mis.m function for details. The graph must be symmetric with a zero-free diagonal, so A is symmetrized first and any diagonal entries are removed.

A = GrB (A) ;
-A = GrB.offdiag (A|A') ;
-
-tic
-s = GrB.mis (A) ;
-toc
-fprintf ('# nodes in the graph: %g\n', size (A,1)) ;
-fprintf ('# edges: : %g\n', GrB.entries (A) / 2) ;
-fprintf ('size of maximal independent set found: %g\n', ...
-    full (double (sum (s)))) ;
-
-% make sure it's independent
-p = find (s) ;
-S = A (p,p) ;
-assert (GrB.entries (S) == 0)
-
-% make sure it's maximal
-notp = find (s == 0) ;
-S = A (notp, p) ;
-deg = GrB.vreduce ('+.int64', S) ;
-assert (logical (all (deg > 0)))
-
Elapsed time is 0.417903 seconds.
-# nodes in the graph: 100000
-# edges: : 9.9899e+06
-size of maximal independent set found: 2811
-

Sparse deep neural network

The 2019 MIT GraphChallenge (see http://graphchallenge.org) is to solve a set of large sparse deep neural network problems. In this demo, the MATLAB reference solution is compared with a solution using GraphBLAS, for a randomly constructed neural network. See the GrB.dnn and dnn_matlab.m functions for details.

clear all
-rng ('default') ;
-nlayers = 16 ;
-nneurons = 4096 ;
-nfeatures = 30000 ;
-fprintf ('# layers:   %d\n', nlayers) ;
-fprintf ('# neurons:  %d\n', nneurons) ;
-fprintf ('# features: %d\n', nfeatures) ;
-
-tic
-Y0 = sprand (nfeatures, nneurons, 0.1) ;
-for layer = 1:nlayers
-    W {layer} = sprand (nneurons, nneurons, 0.01) * 0.2 ;
-    bias {layer} = -0.2 * ones (1, nneurons) ;
-end
-t_setup = toc ;
-fprintf ('construct problem time: %g sec\n', t_setup) ;
-
-% convert the problem from MATLAB to GraphBLAS
-t = tic ;
-[W_gb, bias_gb, Y0_gb] = dnn_mat2gb (W, bias, Y0) ;
-t = toc (t) ;
-fprintf ('setup time: %g sec\n', t) ;
-
# layers:   16
-# neurons:  4096
-# features: 30000
-construct problem time: 6.00243 sec
-setup time: 0.36087 sec
-

Solving the sparse deep neural network problem with GraphbLAS

Please wait ...

tic
-Y1 = GrB.dnn (W_gb, bias_gb, Y0_gb) ;
-gb_time = toc ;
-fprintf ('total time in GraphBLAS: %g sec\n', gb_time) ;
-
total time in GraphBLAS: 12.1395 sec
-

Solving the sparse deep neural network problem with MATLAB

Please wait ...

tic
-Y2 = dnn_matlab (W, bias, Y0) ;
-matlab_time = toc ;
-fprintf ('total time in MATLAB:    %g sec\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
-err = norm (Y1-Y2,1)
-
total time in MATLAB:    81.4066 sec
-Speedup of GraphBLAS over MATLAB: 6.7059
-err =
-     0
-

For objects, GraphBLAS has better colon notation than MATLAB

The MATLAB notation C = A (start:inc:fini) is very handy, and it works great if A is a MATLAB matrix. But for objects like the GraphBLAS matrix, MATLAB starts by creating the explicit index vector I = start:inc:fini. That's fine if the matrix is modest in size, but GraphBLAS can construct huge matrices. The problem is that 1:n cannot be explicitly constructed when n is huge.

The C API for GraphBLAS can represent the colon notation start:inc:fini in an implicit manner, so it can do the indexing without actually forming the explicit list I = start:inc:fini. But there is no access to this method using the MATLAB notation start:inc:fini.

Thus, to compute C = A (start:inc:fini) for very huge matrices, you need to use use a cell array to represent the colon notation, as { start, inc, fini }, instead of start:inc:fini. See 'help GrB.extract' and 'help.gbsubassign' for, for C(I,J)=A. The syntax isn't conventional, but it is far faster than the MATLAB colon notation for objects, and takes far less memory when I is huge.

n = 1e14 ;
-H = GrB (n, n) ;            % a huge empty matrix
-I = [1 1e9 1e12 1e14] ;
-M = magic (4)
-H (I,I) = M ;
-J = {1, 1e13} ;            % represents 1:1e13 colon notation
-C1 = H (J, J)              % computes C1 = H (1:e13,1:1e13)
-c = nonzeros (C1) ;
-m = nonzeros (M (1:3, 1:3)) ;
-assert (isequal (c, m)) ;
-
M =
-    16     2     3    13
-     5    11    10     8
-     9     7     6    12
-     4    14    15     1
-
-C1 =
-
-  10000000000000x10000000000000 GraphBLAS double matrix, hypersparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)    16
-    (1000000000,1)    5
-    (1000000000000,1)    9
-    (1,1000000000)    2
-    (1000000000,1000000000)    11
-    (1000000000000,1000000000)    7
-    (1,1000000000000)    3
-    (1000000000,1000000000000)    10
-    (1000000000000,1000000000000)    6
-
-
try
-    % try to compute the same thing with colon
-    % notation (1:1e13), but this fails:
-    C2 = H (1:1e13, 1:1e13)
-catch me
-    error_expected = me
-end
-
error_expected = 
-  MException with properties:
-
-    identifier: 'MATLAB:array:SizeLimitExceeded'
-       message: 'Requested 10000000000000x1 (74505.8GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See <a href="matlab: helpview([docroot '/matlab/helptargets.map'], 'matlab_env_workspace_prefs')">array size limit</a> or preference panel for more information.'
-         cause: {}
-         stack: [4x1 struct]
-    Correction: []
-

Iterative solvers work as-is

Many built-in functions work with GraphBLAS matrices unmodified.

A = sparse (rand (4)) ;
-b = sparse (rand (4,1)) ;
-x = gmres (A,b)
-norm (A*x-b)
-x = gmres (GrB(A), GrB(b))
-norm (A*x-b)
-
gmres converged at iteration 4 to a solution with relative residual 0.
-x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
-ans =
-   8.6711e-16
-gmres converged at iteration 4 to a solution with relative residual 0.
-x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
-ans =
-   7.2802e-16
-

... even in single precision

x = gmres (GrB(A,'single'), GrB(b,'single'))
-norm (A*x-b)
-
gmres converged at iteration 4 to a solution with relative residual 0.
-x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
-ans =
-   3.6346e-07
-

Both of the following uses of minres (A,b) fail to converge because A is not symmetric, as the method requires. Both failures are correctly reported, and both the MATLAB version and the GraphBLAS version return the same incorrect vector x.

x = minres (A, b)
-x = minres (GrB(A), GrB(b))
-
minres stopped at iteration 4 without converging to the desired tolerance 1e-06
-because the maximum number of iterations was reached.
-The iterate returned (number 4) has relative residual 0.21.
-x =
-    0.2489
-    0.2081
-    0.0700
-    0.3928
-minres stopped at iteration 4 without converging to the desired tolerance 1e-06
-because the maximum number of iterations was reached.
-The iterate returned (number 4) has relative residual 0.21.
-
-x =
-
-  4x1 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.248942
-    (2,1)    0.208128
-    (3,1)    0.0699707
-    (4,1)    0.392812
-
-

With a proper symmetric matrix

A = A+A' ;
-x = minres (A, b)
-norm (A*x-b)
-x = minres (GrB(A), GrB(b))
-norm (A*x-b)
-
minres converged at iteration 4 to a solution with relative residual 1.3e-11.
-x =
- -114.0616
-   -1.4211
-  134.8227
-    2.0694
-ans =
-   1.3650e-11
-minres converged at iteration 4 to a solution with relative residual 1.3e-11.
-
-x =
-
-  4x1 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    -114.062
-    (2,1)    -1.4211
-    (3,1)    134.823
-    (4,1)    2.0694
-
-ans =
-   1.3650e-11
-

Extreme performance differences between GraphBLAS and MATLAB.

The GraphBLAS operations used so far are perhaps 2x to 50x faster than the corresponding MATLAB operations, depending on how many cores your computer has. To run a demo illustrating a 500x or more speedup versus MATLAB, run this demo:

  gbdemo2

It will illustrate an assignment C(I,J)=A that can take under a second in GraphBLAS but several minutes in MATLAB. To make the comparsion even more dramatic, try:

  gbdemo2 (20000)

assuming you have enough memory. The gbdemo2 is not part of this demo since it can take a long time; it tries a range of problem sizes, and each one takes several minutes in MATLAB.

Sparse logical indexing is much, much faster in GraphBLAS

The mask in GraphBLAS acts much like logical indexing in MATLAB, but it is not quite the same. MATLAB logical indexing takes the form:

     C (M) = A (M)

which computes the same thing as the GraphBLAS statement:

     C = GrB.assign (C, M, A)

The GrB.assign statement computes C(M)=A(M), and it is vastly faster than C(M)=A(M), even if the time to convert the GrB matrix back to a MATLAB sparse matrix is included.

GraphBLAS can also compute C (M) = A (M) using overloaded operators for subsref and subsasgn, but C = GrB.assign (C, M, A) is a bit faster.

First, both methods in GraphBLAS (both are very fast):

clear
-n = 4000 ;
-tic
-C = sprand (n, n, 0.1) ;
-A = 100 * sprand (n, n, 0.1) ;
-M = (C > 0.5) ;
-t_setup = toc ;
-fprintf ('nnz(C): %g, nnz(M): %g, nnz(A): %g\n', ...
-    nnz(C), nnz(M), nnz(A)) ;
-fprintf ('\nsetup time:     %g sec\n', t_setup) ;
-
-% include the time to convert C1 from a GraphBLAS
-% matrix to a MATLAB sparse matrix:
-tic
-C1 = GrB.assign (C, M, A) ;
-C1 = double (C1) ;
-gb_time = toc ;
-fprintf ('\nGraphBLAS time: %g sec for GrB.assign\n', gb_time) ;
-
-% now using overloaded operators, also include the time to
-% convert back to a MATLAB sparse matrix, for good measure:
-A2 = GrB (A) ;
-C2 = GrB (C) ;
-tic
-C2 (M) = A2 (M) ;
-C2 = double (C2) ;
-gb_time2 = toc ;
-fprintf ('\nGraphBLAS time: %g sec for C(M)=A(M)\n', gb_time2) ;
-
nnz(C): 1.5226e+06, nnz(M): 761163, nnz(A): 1.52245e+06
-
-setup time:     0.980262 sec
-
-GraphBLAS time: 0.047331 sec for GrB.assign
-
-GraphBLAS time: 0.09221 sec for C(M)=A(M)
-

Please wait, this will take about 10 minutes or so ...

tic
-C (M) = A (M) ;
-matlab_time = toc ;
-
-fprintf ('\nGraphBLAS time: %g sec (GrB.assign)\n', gb_time) ;
-fprintf ('\nGraphBLAS time: %g sec (overloading)\n', gb_time2) ;
-fprintf ('MATLAB time:    %g sec\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time2) ;
-
-% GraphBLAS computes the exact same result with both methods:
-assert (isequal (C1, C))
-assert (isequal (C2, C))
-C1 - C
-C2 - C
-
-GraphBLAS time: 0.047331 sec (GrB.assign)
-
-GraphBLAS time: 0.09221 sec (overloading)
-MATLAB time:    560.273 sec
-Speedup of GraphBLAS over MATLAB: 6076.05
-ans =
-   All zero sparse: 4000x4000
-ans =
-   All zero sparse: 4000x4000
-

Limitations and their future solutions

The MATLAB interface for SuiteSparse:GraphBLAS is a work-in-progress. It has some limitations, most of which will be resolved over time.

(1) Nonblocking mode:

GraphBLAS has a 'non-blocking' mode, in which operations can be left pending and completed later. SuiteSparse:GraphBLAS uses the non-blocking mode to speed up a sequence of assignment operations, such as C(I,J)=A. However, in its MATLAB interface, this would require a MATLAB mexFunction to modify its inputs. That breaks the MATLAB API standard, so it cannot be safely done. As a result, using GraphBLAS via its MATLAB interface can be slower than when using its C API. This restriction would not be a limitation if GraphBLAS were to be incorporated into MATLAB itself, but there is likely no way to do this in a mexFunction interface to GraphBLAS.

(2) Complex matrices:

GraphBLAS can operate on matrices with arbitrary user-defined types and operators. The only constraint is that the type be a fixed sized typedef that can be copied with the ANSI C memcpy; variable-sized types are not yet supported. However, in this MATLAB interface, SuiteSparse:GraphBLAS has access to only predefined types, operators, and semirings. Complex types and operators will be added to this MATLAB interface in the future. They already appear in the C version of GraphBLAS, with user-defined operators in GraphBLAS/Demo/Source/usercomplex.c.

(3) Integer element-wise operations:

Integer operations in MATLAB saturate, so that uint8(255)+1 is 255. To allow for integer monoids, GraphBLAS uses modular arithmetic instead. This is the only way that C=A*B can be defined for integer semirings. However, saturating integer operators could be added in the future, so that element- wise integer operations on GraphBLAS sparse integer matrices could work just the same as their MATLAB counterparts.

So in the future, you could perhaps write this, for both sparse and dense integer matrices A and B:

     C = GrB.eadd ('+saturate.int8', A, B)

to compute the same thing as C=A+B in MATLAB for its full int8 matrices. Note that MATLAB can do this only for dense integer matrices, since it doesn't support sparse integer matrices.

(4) Faster methods:

Most methods in this MATLAB interface are based on efficient parallel C functions in GraphBLAS itself, and are typically as fast or faster than the equivalent built-in operators and functions in MATLAB.

There are few notable exceptions; these will be addressed in the future. Dense matrices and vectors held as GraphBLAS objects are slower than their MATLAB counterparts. horzcat and vertcat, for [A B] and [A;B] when either A or B are GraphBLAS matrices, are also slow, as illustrated below in the next example.

Other methods that will be faster in the future include bandwidth, istriu, istril, eps, ceil, floor, round, fix, isfinite, isinf, isnan, spfun, and A.^B. These methods are currently implemented in m-files, not in efficient parallel C functions.

Here is an example that illustrates the performance of C = [A B]

clear
-A = sparse (rand (2000)) ;
-B = sparse (rand (2000)) ;
-tic
-C1 = [A B] ;
-matlab_time = toc ;
-
-A = GrB (A) ;
-B = GrB (B) ;
-tic
-C2 = [A B] ;
-gb_time = toc ;
-
-err = norm (C1-C2,1)
-fprintf ('\nMATLAB: %g sec, GraphBLAS: %g sec\n', ...
-    matlab_time, gb_time) ;
-if (gb_time > matlab_time)
-    fprintf ('GraphBLAS is slower by a factor of %g\n', ...
-        gb_time / matlab_time) ;
-end
-
err =
-     0
-
-MATLAB: 0.039462 sec, GraphBLAS: 0.12575 sec
-GraphBLAS is slower by a factor of 3.18661
-

(5) Linear indexing:

If A is an m-by-n 2D MATLAB matrix, with n > 1, A(:) is a column vector of length m*n. The index operation A(i) accesses the ith entry in the vector A(:). This is called linear indexing in MATLAB. It is not yet available for GraphBLAS matrices in this MATLAB interface to GraphBLAS, but it could be added in the future.

(6) Implicit singleton dimension expansion

In MATLAB C=A+B where A is m-by-n and B is a 1-by-n row vector implicitly expands B to a matrix, computing C(i,j)=A(i,j)+B(j). This implicit expansion is not yet suported in GraphBLAS with C=A+B. However, it can be done with C = GrB.mxm ('+.+', A, diag(GrB(B))). That's an nice example of the power of semirings, but it's not immediately obvious, and not as clear a syntax as C=A+B. The GraphBLAS/@GrB/dnn.m function uses this 'plus.plus' semiring to apply the bias to each neuron.

A = magic (3)
-B = 1000:1000:3000
-C1 = A + B
-C2 = GrB.mxm ('+.+', A, diag (GrB (B)))
-err = norm (C1-C2,1)
-
A =
-     8     1     6
-     3     5     7
-     4     9     2
-B =
-        1000        2000        3000
-C1 =
-        1008        2001        3006
-        1003        2005        3007
-        1004        2009        3002
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)    1008
-    (2,1)    1003
-    (3,1)    1004
-    (1,2)    2001
-    (2,2)    2005
-    (3,2)    2009
-    (1,3)    3006
-    (2,3)    3007
-    (3,3)    3002
-
-err =
-     0
-

GraphBLAS operations

In addition to the overloaded operators (such as C=A*B) and overloaded functions (such as L=tril(A)), GraphBLAS also has methods of the form GrB.method, listed on the next page. Most of them take an optional input matrix Cin, which is the initial value of the matrix C for the expression below, an optional mask matrix M, and an optional accumulator operator.

    C<#M,replace> = accum (C, T)

In the above expression, #M is either empty (no mask), M (with a mask matrix) or ~M (with a complemented mask matrix), as determined by the descriptor. 'replace' can be used to clear C after it is used in accum(C,T) but before it is assigned with C<...> = Z, where Z=accum(C,T). The matrix T is the result of some operation, such as T=A*B for GrB.mxm, or T=op(A,B) for GrB.eadd.

A summary of these GrB.methods is on the next pages.

Methods for the GrB class:

These methods operate on GraphBLAS matrices only, and they overload
-the existing MATLAB functions of the same name.
-
C = GrB (...)           construct a GraphBLAS matrix
-C = sparse (G)          makes a copy of a GrB matrix
-C = full (G, ...)       adds explicit zeros or id values to a GrB matrix
-C = double (G)          cast GrB matrix to MATLAB sparse double matrix
-C = logical (G)         cast GrB matrix to MATLAB sparse logical matrix
-C = complex (G)         cast GrB matrix to MATLAB sparse complex
-C = single (G)          cast GrB matrix to MATLAB full single matrix
-C = int8 (G)            cast GrB matrix to MATLAB full int8 matrix
-C = int16 (G)           cast GrB matrix to MATLAB full int16 matrix
-C = int32 (G)           cast GrB matrix to MATLAB full int32 matrix
-C = int64 (G)           cast GrB matrix to MATLAB full int64 matrix
-C = uint8 (G)           cast GrB matrix to MATLAB full uint8 matrix
-C = uint16 (G)          cast GrB matrix to MATLAB full uint16 matrix
-C = uint32 (G)          cast GrB matrix to MATLAB full uint32 matrix
-C = uint64 (G)          cast GrB matrix to MATLAB full uint64 matrix
-C = cast (G,...)        cast GrB matrix to MATLAB matrix (as above)
-
X = nonzeros (G)        extract all entries from a GrB matrix
-[I,J,X] = find (G)      extract all entries from a GrB matrix
-C = spones (G)          return pattern of GrB matrix
-disp (G, level)         display a GrB matrix G
-display (G)             display a GrB matrix G; same as disp(G,2)
-mn = numel (G)          m*n for an m-by-n GrB matrix G
-e = nnz (G)             number of entries in a GrB matrix G
-e = nzmax (G)           number of entries in a GrB matrix G
-[m n] = size (G)        size of a GrB matrix G
-n = length (G)          length of a GrB vector
-s = isempty (G)         true if any dimension of G is zero
-s = issparse (G)        true for any GrB matrix G
-s = ismatrix (G)        true for any GrB matrix G
-s = isvector (G)        true if m=1 or n=1, for an m-by-n GrB matrix G
-s = iscolumn (G)        true if n=1, for an m-by-n GrB matrix G
-s = isrow (G)           true if m=1, for an m-by-n GrB matrix G
-s = isscalar (G)        true if G is a 1-by-1 GrB matrix
-s = isnumeric (G)       true for any GrB matrix G (even logical)
-s = isfloat (G)         true if GrB matrix is double, single, complex
-s = isreal (G)          true if GrB matrix is not complex
-s = isinteger (G)       true if GrB matrix is int8, int16, ..., uint64
-s = islogical (G)       true if GrB matrix is logical
-s = isa (G, classname)  check if a GrB matrix is of a specific class
-
C = diag (G,k)          diagonal matrices and diagonals of GrB matrix G
-L = tril (G,k)          lower triangular part of GrB matrix G
-U = triu (G,k)          upper triangular part of GrB matrix G
-C = kron (A,B)          Kronecker product
-C = repmat (G, ...)     replicate and tile a GraphBLAS matrix
-C = reshape (G, ...)    reshape a GraphBLAS matrix
-C = abs (G)             absolute value
-C = sign (G)            signum function
-s = istril (G)          true if G is lower triangular
-s = istriu (G)          true if G is upper triangular
-s = isbanded (G,...)    true if G is banded
-s = isdiag (G)          true if G is diagonal
-s = ishermitian (G)     true if G is Hermitian
-s = issymmetric (G)     true if G is symmetric
-[lo,hi] = bandwidth (G) determine the lower & upper bandwidth of G
-C = sum (G, option)     reduce via sum, to vector or scalar
-C = prod (G, option)    reduce via product, to vector or scalar
-s = norm (G, kind)      1-norm or inf-norm of a GrB matrix
-C = max (G, ...)        reduce via max, to vector or scalar
-C = min (G, ...)        reduce via min, to vector or scalar
-C = any (G, ...)        reduce via '|', to vector or scalar
-C = all (G, ...)        reduce via '&', to vector or scalar
-
C = sqrt (G)            element-wise square root
-C = eps (G)             floating-point spacing
-C = ceil (G)            round towards infinity
-C = floor (G)           round towards -infinity
-C = round (G)           round towards nearest
-C = fix (G)             round towards zero
-C = isfinite (G)        test if finite
-C = isinf (G)           test if infinite
-C = isnan (G)           test if NaN
-C = spfun (fun, G)      evaluate a function on the entries of G
-p = amd (G)             approximate minimum degree ordering
-p = colamd (G)          column approximate minimum degree ordering
-p = symamd (G)          approximate minimum degree ordering
-p = symrcm (G)          reverse Cuthill-McKee ordering
-[...] = dmperm (G)      Dulmage-Mendelsohn permutation
-parent = etree (G)      elimination tree
-C = conj (G)            complex conjugate
-C = real (G)            real part of a complex GraphBLAS matrix
-[V, ...] = eig (G,...)  eigenvalues and eigenvectors
-assert (G)              generate an error if G is false
-C = zeros (...,'like',G)   all-zero matrix, same type as G
-C = false (...,'like',G)   all-false logical matrix
-C = ones (...,'like',G)    matrix with all ones, same type as G
-

Operator overloading:

C = plus (A, B)         C = A + B
-C = minus (A, B)        C = A - B
-C = uminus (G)          C = -G
-C = uplus (G)           C = +G
-C = times (A, B)        C = A .* B
-C = mtimes (A, B)       C = A * B
-C = rdivide (A, B)      C = A ./ B
-C = ldivide (A, B)      C = A .\ B
-C = mrdivide (A, B)     C = A / B
-C = mldivide (A, B)     C = A \ B
-C = power (A, B)        C = A .^ B
-C = mpower (A, B)       C = A ^ B
-C = lt (A, B)           C = A < B
-C = gt (A, B)           C = A > B
-C = le (A, B)           C = A <= B
-C = ge (A, B)           C = A >= B
-C = ne (A, B)           C = A ~= B
-C = eq (A, B)           C = A == B
-C = and (A, B)          C = A & B
-C = or (A, B)           C = A | B
-C = not (G)             C = ~G
-C = ctranspose (G)      C = G'
-C = transpose (G)       C = G.'
-C = horzcat (A, B)      C = [A , B]
-C = vertcat (A, B)      C = [A ; B]
-C = subsref (A, I, J)   C = A (I,J) or C = A (M)
-C = subsasgn (A, I, J)  C (I,J) = A
-index = end (A, k, n)   for object indexing, A(1:end,1:end)
-

Static Methods:

The Static Methods for the GrB class can be used on input matrices of
-any kind: GraphBLAS sparse matrices, MATLAB sparse matrices, or
-MATLAB dense matrices, in any combination.  The output matrix Cout is
-a GraphBLAS matrix, by default, but can be optionally returned as a
-MATLAB sparse or dense matrix.  The static methods divide into two
-categories: those that perform basic functions, and the GraphBLAS
-operations that use the mask/accum.
-

GraphBLAS basic functions:

GrB.clear                    clear GraphBLAS workspace and settings
-GrB.descriptorinfo (d)       list properties of a descriptor
-GrB.unopinfo (op, type)      list properties of a unary operator
-GrB.binopinfo (op, type)     list properties of a binary operator
-GrB.monoidinfo (op, type)    list properties of a monoid
-GrB.semiringinfo (s, type)   list properties of a semiring
-t = GrB.threads (t)          set/get # of threads to use in GraphBLAS
-c = GrB.chunk (c)            set/get chunk size to use in GraphBLAS
-result = GrB.entries (G,...) count or query entries in a matrix
-result = GrB.nonz (G,...)    count or query nonzeros in a matrix
-C = GrB.prune (A, id)        prune entries equal to id
-C = GrB.offdiag (A)          prune diagonal entries
-s = GrB.isfull (A)           true if all entries present
-[C,I,J] = GrB.compact (A,id) remove empty rows and columns
-G = GrB.empty (m, n)         return an empty GraphBLAS matrix
-s = GrB.type (A)             get the type of a MATLAB or GrB matrix A
-s = GrB.issigned (type)      true if type is signed
-f = GrB.format (f)           set/get matrix format to use in GraphBLAS
-s = GrB.isbyrow (A)          true if format f A is 'by row'
-s = GrB.isbycol (A)          true if format f A is 'by col'
-C = GrB.expand (scalar, A)   expand a scalar (C = scalar*spones(A))
-C = GrB.eye                  identity matrix of any type
-C = GrB.speye                identity matrix (of type 'double')
-C = GrB.build (I, J, X, m, n, dup, type, desc)
-                             build a GrB matrix from list of entries
-[I,J,X] = GrB.extracttuples (A, desc)
-                             extract all entries from a matrix
-

GraphBLAS operations with Cout, mask M, and accum.

Cout = GrB.mxm (Cin, M, accum, semiring, A, B, desc)
-                sparse matrix-matrix multiplication over a semiring
-Cout = GrB.select (Cin, M, accum, op, A, b, desc)
-                select a subset of entries from a matrix
-Cout = GrB.assign (Cin, M, accum, A, I, J, desc)
-                sparse matrix assignment, such as C(I,J)=A
-Cout = GrB.subassign (Cin, M, accum, A, I, J, desc)
-                sparse matrix assignment, such as C(I,J)=A
-Cout = GrB.vreduce (Cin, M, accum, op, A, desc)
-                reduce a matrix to a vector
-Cout = GrB.reduce (Cin, accum, op, A, desc)
-                reduce a matrix to a scalar
-Cout = GrB.kronecker (Cin, M, accum, op, A, B, desc)
-                Kronecker product
-Cout = GrB.trans (Cin, M, accum, A, desc)
-                transpose a matrix
-Cout = GrB.eadd (Cin, M, accum, op, A, B, desc)
-                element-wise addition
-Cout = GrB.emult (Cin, M, accum, op, A, B, desc)
-                element-wise multiplication
-Cout = GrB.apply (Cin, M, accum, op, A, desc)
-                apply a unary operator
-Cout = GrB.extract (Cin, M, accum, A, I, J, desc)
-                extract submatrix, like C=A(I,J) in MATLAB
-

GraphBLAS operations (with Cout, Cin arguments) take the following form:

C<#M,replace> = accum (C, operation (A or A', B or B'))
-
C is both an input and output matrix.  In this MATLAB interface to
-GraphBLAS, it is split into Cin (the value of C on input) and Cout
-(the value of C on output).  M is the optional mask matrix, and #M is
-either M or !M depending on whether or not the mask is complemented
-via the desc.mask option.  The replace option is determined by
-desc.out; if present, C is cleared after it is used in the accum
-operation but before the final assignment.  A and/or B may optionally
-be transposed via the descriptor fields desc.in0 and desc.in1,
-respectively.  To select the format of Cout, use desc.format.  See
-GrB.descriptorinfo for more details.
-
accum is optional; if not is not present, then the operation becomes
-C<...> = operation(A,B).  Otherwise, C = C + operation(A,B) is
-computed where '+' is the accum operator.  It acts like a sparse
-matrix addition (see GrB.eadd), in terms of the structure of the
-result C, but any binary operator can be used.
-
The mask M acts like MATLAB logical indexing.  If M(i,j)=1 then
-C(i,j) can be modified; if zero, it cannot be modified by the
-operation.
-

Static Methods for graph algorithms:

r = GrB.pagerank (A, opts) ;            % PageRank of a matrix
-C = GrB.ktruss (A, k, check) ;          % k-truss
-s = GrB.tricount (A, check) ;           % triangle count
-L = GrB.laplacian (A, type, check) ;    % Laplacian graph
-C = GrB.incidence (A, ...) ;            % incidence matrix
-[v, parent] = GrB.bfs (A, s, ...) ;     % breadth-first search
-iset = GrB.mis (A, check) ;             % maximal independent set
-Y = GrB.dnn (W, bias, Y0) ;             % deep neural network
-
More graph algorithms will be added in the future.
-

Thanks for watching!

Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis See also sparse, doc sparse, and https://twitter.com/DocSparse

\ No newline at end of file diff --git a/GraphBLAS/demo/html/DellXPS13/v320/graphblas_demo.html b/GraphBLAS/demo/html/DellXPS13/v320/graphblas_demo.html deleted file mode 100644 index 06d933abba..0000000000 --- a/GraphBLAS/demo/html/DellXPS13/v320/graphblas_demo.html +++ /dev/null @@ -1,2693 +0,0 @@ - - - - - GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS is a library for creating graph algorithms based on sparse linear algebraic operations over semirings. Visit http://graphblas.org for more details and resources. See also the SuiteSparse:GraphBLAS User Guide in this package.

SuiteSparse:GraphBLAS, (c) 2017-2020, Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis

Contents

GraphBLAS: faster and more general sparse matrices for MATLAB

GraphBLAS is not only useful for creating graph algorithms; it also supports a wide range of sparse matrix data types and operations. MATLAB can compute C=A*B with just two semirings: 'plus.times.double' and 'plus.times.complex' for complex matrices. GraphBLAS has 1,040 unique built-in semirings, such as 'max.plus' (https://en.wikipedia.org/wiki/Tropical_semiring). These semirings can be used to construct a wide variety of graph algorithms, based on operations on sparse adjacency matrices.

GraphBLAS supports sparse double and single precision matrices, logical, and sparse integer matrices: int8, int16, int32, int64, uint8, uint16, uint32, and uint64. Complex matrices will be added in the future.

clear all
-format compact
-rng ('default') ;
-X = 100 * rand (2) ;
-G = GrB (X)              % GraphBLAS copy of a matrix X, same type
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    81.4724
-    (2,1)    90.5792
-    (1,2)    12.6987
-    (2,2)    91.3376
-
-

Sparse integer matrices

Here's an int8 version of the same matrix:

S = int8 (G)            % convert G to a full MATLAB int8 matrix
-G = GrB (X, 'int8')      % a GraphBLAS sparse int8 matrix
-
S =
-  2x2 int8 matrix
-   81   12
-   90   91
-
-G =
-
-  2x2 GraphBLAS int8_t matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)   81
-    (2,1)   90
-    (1,2)   12
-    (2,2)   91
-
-

Sparse single-precision matrices

Matrix operations in GraphBLAS are typically as fast, or faster than MATLAB. Here's an unfair comparison: computing X^2 with MATLAB in double precision and with GraphBLAS in single precision. You would naturally expect GraphBLAS to be faster.

Please wait ...

n = 1e5 ;
-X = spdiags (rand (n, 201), -100:100, n, n) ;
-G = GrB (X, 'single') ;
-tic
-G2 = G^2 ;
-gb_time = toc ;
-tic
-X2 = X^2 ;
-matlab_time = toc ;
-fprintf ('\nGraphBLAS time: %g sec (in single)\n', gb_time) ;
-fprintf ('MATLAB time:    %g sec (in double)\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
-GraphBLAS time: 1.88612 sec (in single)
-MATLAB time:    6.23295 sec (in double)
-Speedup of GraphBLAS over MATLAB: 3.30465
-

Mixing MATLAB and GraphBLAS matrices

The error in the last computation is about eps('single') since GraphBLAS did its computation in single precision, while MATLAB used double precision. MATLAB and GraphBLAS matrices can be easily combined, as in X2-G2. The sparse single precision matrices take less memory space.

err = norm (X2 - G2, 1) / norm (X2,1)
-eps ('single')
-whos G G2 X X2
-
err =
-   1.5049e-07
-ans =
-  single
-  1.1921e-07
-  Name           Size                    Bytes  Class     Attributes
-
-  G         100000x100000            241879772  GrB                 
-  G2        100000x100000            481518572  GrB                 
-  X         100000x100000            322238408  double    sparse    
-  X2        100000x100000            641756808  double    sparse    
-
-

Faster matrix operations

But even with standard double precision sparse matrices, GraphBLAS is typically faster than the built-in MATLAB methods. Here's a fair comparison:

G = GrB (X) ;
-tic
-G2 = G^2 ;
-gb_time = toc ;
-err = norm (X2 - G2, 1) / norm (X2,1)
-fprintf ('\nGraphBLAS time: %g sec (in double)\n', gb_time) ;
-fprintf ('MATLAB time:    %g sec (in double)\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
err =
-     0
-
-GraphBLAS time: 2.50213 sec (in double)
-MATLAB time:    6.23295 sec (in double)
-Speedup of GraphBLAS over MATLAB: 2.49105
-

A wide range of semirings

MATLAB can only compute C=A*B using the standard '+.*.double' and '+.*.complex' semirings. A semiring is defined in terms of a string, 'add.mult.type', where 'add' is a monoid that takes the place of the additive operator, 'mult' is the multiplicative operator, and 'type' is the data type for the two inputs to the mult operator (the type defaults to the type of A for C=A*B).

In the standard semiring, C=A*B is defined as:

C(i,j) = sum (A(i,:).' .* B(:,j))
-

using 'plus' as the monoid and 'times' as the multiplicative operator. But in a more general semiring, 'sum' can be any monoid, which is an associative and commutative operator that has an identity value. For example, in the 'max.plus' tropical algebra, C(i,j) for C=A*B is defined as:

C(i,j) = max (A(i,:).' + B(:,j))
-

This can be computed in GraphBLAS with:

C = GrB.mxm ('max.+', A, B)
-
n = 3 ;
-A = rand (n) ;
-B = rand (n) ;
-C = zeros (n) ;
-for i = 1:n
-    for j = 1:n
-        C(i,j) = max (A (i,:).' + B (:,j)) ;
-    end
-end
-C2 = GrB.mxm ('max.+', A, B) ;
-fprintf ('\nerr = norm (C-C2,1) = %g\n', norm (C-C2,1)) ;
-
-err = norm (C-C2,1) = 0
-

The max.plus tropical semiring

Here are details of the "max.plus" tropical semiring. The identity value is -inf since max(x,-inf) = max (-inf,x) = -inf for any x.

GrB.semiringinfo ('max.+.double') ;
-
-    GraphBLAS Semiring: max.+.double (built-in)
-    GraphBLAS Monoid: semiring->add (built-in)
-    GraphBLAS BinaryOp: monoid->op (built-in) z=max(x,y)
-    GraphBLAS type: ztype double size: 8
-    GraphBLAS type: xtype double size: 8
-    GraphBLAS type: ytype double size: 8
-    identity: [    -inf ] terminal: [    inf ]
-
-    GraphBLAS BinaryOp: semiring->multiply (built-in) z=plus(x,y)
-    GraphBLAS type: ztype double size: 8
-    GraphBLAS type: xtype double size: 8
-    GraphBLAS type: ytype double size: 8
-

A boolean semiring

MATLAB cannot multiply two logical matrices. MATLAB R2019a converts them to double and uses the conventional +.*.double semiring instead. In GraphBLAS, this is the common Boolean 'or.and.logical' semiring, which is widely used in linear algebraic graph algorithms.

GrB.semiringinfo ('|.&.logical') ;
-
-    GraphBLAS Semiring: |.&.logical (built-in)
-    GraphBLAS Monoid: semiring->add (built-in)
-    GraphBLAS BinaryOp: monoid->op (built-in) z=or(x,y)
-    GraphBLAS type: ztype bool size: 1
-    GraphBLAS type: xtype bool size: 1
-    GraphBLAS type: ytype bool size: 1
-    identity: [   0 ] terminal: [   1 ]
-
-    GraphBLAS BinaryOp: semiring->multiply (built-in) z=and(x,y)
-    GraphBLAS type: ztype bool size: 1
-    GraphBLAS type: xtype bool size: 1
-    GraphBLAS type: ytype bool size: 1
-
clear
-A = sparse (rand (3) > 0.5)
-B = sparse (rand (3) > 0.2)
-
A =
-  3x3 sparse logical array
-   (2,1)      1
-   (2,2)      1
-   (3,2)      1
-   (1,3)      1
-B =
-  3x3 sparse logical array
-   (1,1)      1
-   (2,1)      1
-   (3,1)      1
-   (1,2)      1
-   (2,2)      1
-   (3,2)      1
-   (1,3)      1
-   (2,3)      1
-   (3,3)      1
-
try
-    % MATLAB R2019a does this by casting A and B to double
-    C1 = A*B
-catch
-    % MATLAB R2018a throws an error
-    fprintf ('MATLAB R2019a required for C=A*B with logical\n') ;
-    fprintf ('matrices.  Explicitly converting to double:\n') ;
-    C1 = double (A) * double (B)
-end
-C2 = GrB (A) * GrB (B)
-
C1 =
-   (1,1)        1
-   (2,1)        2
-   (3,1)        1
-   (1,2)        1
-   (2,2)        2
-   (3,2)        1
-   (1,3)        1
-   (2,3)        2
-   (3,3)        1
-
-C2 =
-
-  3x3 GraphBLAS bool matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)   1
-    (2,1)   1
-    (3,1)   1
-    (1,2)   1
-    (2,2)   1
-    (3,2)   1
-    (1,3)   1
-    (2,3)   1
-    (3,3)   1
-
-

Note that C1 is a MATLAB sparse double matrix, and contains non-binary values. C2 is a GraphBLAS logical matrix.

whos
-GrB.type (C2)
-
  Name      Size            Bytes  Class      Attributes
-
-  A         3x3                68  logical    sparse    
-  B         3x3               113  logical    sparse    
-  C1        3x3               176  double     sparse    
-  C2        3x3              1079  GrB                  
-
-ans =
-    'logical'
-

GraphBLAS operators, monoids, and semirings

The C interface for SuiteSparse:GraphBLAS allows for arbitrary types and operators to be constructed. However, the MATLAB interface to SuiteSparse:GraphBLAS is restricted to pre-defined types and operators: a mere 11 types, 66 unary operators, 275 binary operators, 44 monoids, 16 select operators, and 1,865 semirings (1,040 of which are unique, since some binary operators are equivalent: 'min.logical' and '&.logical' are the same thing, for example). The complex type and its binary operators, monoids, and semirings will be added in the near future.

That gives you a lot of tools to create all kinds of interesting graph algorithms. For example:

GrB.bfs    % breadth-first search
-GrB.dnn    % sparse deep neural network (http://graphchallenge.org)
-GrB.mis    % maximal independent set
-

See 'help GrB.binopinfo' for a list of the binary operators, and 'help GrB.monoidinfo' for the ones that can be used as the additive monoid in a semiring.

help GrB.binopinfo
-
 GRB.BINOPINFO list the details of a GraphBLAS binary operator.
- 
-  Usage
- 
-    GrB.binopinfo
-    GrB.binopinfo (op)
-    GrB.binopinfo (op, type)
- 
-  For GrB.binopinfo(op), the op must be a string of the form
-  'op.type', where 'op' is listed below.  The second usage allows the
-  type to be omitted from the first argument, as just 'op'.  This is
-  valid for all GraphBLAS operations, since the type defaults to the
-  type of the input matrices.  However, GrB.binopinfo does not have a
-  default type and thus one must be provided, either in the op as
-  GrB.binopinfo ('+.double'), or in the second argument, GrB.binopinfo
-  ('+', 'double').
- 
-  The MATLAB interface to GraphBLAS provides for 27 different binary
-  operators, each of which may be used with any of the 11 types, for
-  a total of 27*11 = 297 valid binary operators.  Binary operators
-  are defined by a string of the form 'op.type', or just 'op'.  In
-  the latter case, the type defaults to the type of the matrix inputs
-  to the GraphBLAS operation.
- 
-  The 6 comparator operators come in two flavors.  For the is*
-  operators, the result has the same type as the inputs, x and y,
-  with 1 for true and 0 for false.  For example isgt.double (pi, 3.0)
-  is the double value 1.0.  For the second set of 6 operators (eq,
-  ne, gt, lt, ge, le), the result is always logical (true or false).
-  In a semiring, the type of the add monoid must exactly match the
-  type of the output of the multiply operator, and thus
-  'plus.iseq.double' is valid (counting how many terms are equal).
-  The 'plus.eq.double' semiring is valid, but not the same semiring
-  since the 'plus' of 'plus.eq.double' has a logical type and is thus
-  equivalent to 'or.eq.double'.   The 'or.eq' is true if any terms
-  are equal and false otherwise (it does not count the number of
-  terms that are equal).
- 
-  The following binary operators are available.  Many have equivalent
-  synonyms, so that '1st' and 'first' both define the first(x,y) = x
-  operator.
- 
-    operator name(s) f(x,y)         |   operator names(s) f(x,y)
-    ---------------- ------         |   ----------------- ------
-    1st first        x              |   iseq             x == y
-    2nd second       y              |   isne             x ~= y
-    min              min(x,y)       |   isgt             x > y
-    max              max(x,y)       |   islt             x < y
-    +   plus         x+y            |   isge             x >= y
-    -   minus        x-y            |   isle             x <= y
-    rminus           y-x            |   ==  eq           x == y
-    *   times        x*y            |   ~=  ne           x ~= y
-    /   div          x/y            |   >   gt           x > y
-    \   rdiv         y/x            |   <   lt           x < y
-    |   || or  lor   x | y          |   >=  ge           x >= y
-    &   && and land  x & y          |   <=  le           x <= y
-    xor lxor         xor(x,y)       |
-    pair             1              |   any              x, or y
- 
-  The three logical operators, lor, land, and lxor, also come in 11
-  types.  z = lor.double (x,y) tests the condition (x~=0) || (y~=0),
-  and returns the double value 1.0 if true, or 0.0 if false.
- 
-  Example:
- 
-    % valid binary operators
-    GrB.binopinfo ('+.double') ;
-    GrB.binopinfo ('1st.int32') ;
- 
-    % invalid binary operator (an error; this is a unary op):
-    GrB.binopinfo ('abs.double') ;
- 
-  See also GrB.descriptorinfo, GrB.monoidinfo, GrB.selectopinfo,
-  GrB.semiringinfo, GrB.unopinfo.
-
-
help GrB.monoidinfo
-
 GRB.MONOIDINFO list the details of a GraphBLAS monoid.
- 
-  Usage
- 
-    GrB.monoidinfo
-    GrB.monoidinfo (monoid)
-    GrB.monoidinfo (monoid, type)
- 
-  For GrB.monoidinfo(op), the op must be a string of the form
-  'op.type', where 'op' is listed below.  The second usage allows the
-  type to be omitted from the first argument, as just 'op'.  This is
-  valid for all GraphBLAS operations, since the type defaults to the
-  type of the input matrices.  However, GrB.monoidinfo does not have a
-  default type and thus one must be provided, either in the op as
-  GrB.monoidinfo ('+.double'), or in the second argument,
-  GrB.monoidinfo ('+', 'double').
- 
-  The MATLAB interface to GraphBLAS provides for 44 different
-  monoids.  The valid monoids are: '+', '*', 'max', and 'min' for all
-  but the 'logical' type, and '|', '&', 'xor', and 'eq' for the
-  'logical' type.
- 
-  Example:
- 
-    % valid monoids
-    GrB.monoidinfo ('+.double') ;
-    GrB.monoidinfo ('*.int32') ;
- 
-    % invalid monoids
-    GrB.monoidinfo ('1st.int32') ;
-    GrB.monoidinfo ('abs.double') ;
- 
-  See also GrB.binopinfo, GrB.descriptorinfo, % GrB.selectopinfo,
-  GrB.semiringinfo, GrB.unopinfo.
-
-

Element-wise operations

Binary operators can be used in element-wise matrix operations, like C=A+B and C=A.*B. For the matrix addition C=A+B, the pattern of C is the set union of A and B, and the '+' operator is applied for entries in the intersection. Entries in A but not B, or in B but not A, are assigned to C without using the operator. The '+' operator is used for C=A+B but any operator can be used with GrB.eadd.

A = GrB (sprand (3, 3, 0.5)) ;
-B = GrB (sprand (3, 3, 0.5)) ;
-C1 = A + B
-C2 = GrB.eadd ('+', A, B)
-err = norm (C1-C2,1)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    1.47841
-    (2,2)    0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    1.47841
-    (2,2)    0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-err =
-     0
-

Subtracting two matrices

A-B and GrB.eadd ('-', A, B) are not the same thing, since the '-' operator is not applied to an entry that is in B but not A.

C1 = A-B
-C2 = GrB.eadd ('-', A, B)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    -0.666139
-    (3,1)    -0.735859
-    (1,2)    -0.334348
-    (2,2)    -0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    -0.334348
-    (2,2)    0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-

But these give the same result

C1 = A-B
-C2 = GrB.eadd ('+', A, GrB.apply ('-', B))
-err = norm (C1-C2,1)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    -0.666139
-    (3,1)    -0.735859
-    (1,2)    -0.334348
-    (2,2)    -0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  7 nonzeros, 7 entries
-
-    (1,1)    -0.666139
-    (3,1)    -0.735859
-    (1,2)    -0.334348
-    (2,2)    -0.146938
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-err =
-     0
-

Element-wise 'multiplication'

For C = A.*B, the result C is the set intersection of the pattern of A and B. The operator is applied to entries in both A and B. Entries in A but not B, or B but not A, do not appear in the result C.

C1 = A.*B
-C2 = GrB.emult ('*', A, B)
-C3 = double (A) .* double (B)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  1 nonzero, 1 entry
-
-    (1,2)    0.518474
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  1 nonzero, 1 entry
-
-    (1,2)    0.518474
-
-C3 =
-   (1,2)       0.5185
-

Just as in GrB.eadd, any operator can be used in GrB.emult:

A
-B
-C2 = GrB.emult ('max', A, B)
-
-A =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,2)    0.572029
-    (3,2)    0.566879
-    (2,3)    0.248635
-    (3,3)    0.104226
-
-
-B =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.666139
-    (3,1)    0.735859
-    (1,2)    0.906378
-    (2,2)    0.146938
-
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  1 nonzero, 1 entry
-
-    (1,2)    0.906378
-
-

Overloaded operators

The following operators all work as you would expect for any matrix. The matrices A and B can be GraphBLAS matrices, or MATLAB sparse or dense matrices, in any combination, or scalars where appropriate:

  A+B   A-B  A*B   A.*B  A./B  A.\B  A.^b   A/b   C=A(I,J)
-  -A    +A   ~A    A'    A.'   A&B   A|B    b\A   C(I,J)=A
-  A~=B  A>B  A==B  A<=B  A>=B  A<B   [A,B]  [A;B]
-  A(1:end,1:end)

For A^b, b must be a non-negative integer.

C1 = [A B] ;
-C2 = [double(A) double(B)] ;
-assert (isequal (double (C1), C2))
-
C1 = A^2
-C2 = double (A)^2 ;
-err = norm (C1 - C2, 1)
-assert (err < 1e-12)
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  5 nonzeros, 5 entries
-
-    (2,2)    0.140946
-    (3,2)    0.0590838
-    (1,3)    0.142227
-    (2,3)    0.0259144
-    (3,3)    0.151809
-
-err =
-     0
-
C1 = A (1:2,2:end)
-A = double (A) ;
-C2 = A (1:2,2:end) ;
-assert (isequal (double (C1), C2))
-
-C1 =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  2 nonzeros, 2 entries
-
-    (1,1)    0.572029
-    (2,2)    0.248635
-
-

Overloaded functions

Many MATLAB built-in functions can be used with GraphBLAS matrices:

A few differences with the built-in functions:

S = sparse (G)        % makes a copy of a GrB matrix
-F = full (G)          % adds explicit zeros, so numel(F)==nnz(F)
-F = full (G,type,id)  % adds explicit identity values to a GrB matrix
-disp (G, level)       % display a GrB matrix G; level=2 is the default.
-

In the list below, the first set of Methods are overloaded built-in methods. They are used as-is on GraphBLAS matrices, such as C=abs(G). The Static methods are prefixed with "GrB.", as in C = GrB.apply ( ... ).

methods GrB
-
-Methods for class GrB:
-
-GrB             ge              le              sparse          
-abs             graph           length          spfun           
-all             gt              logical         spones          
-amd             horzcat         lt              sprand          
-and             int16           max             sprandn         
-any             int32           min             sprandsym       
-assert          int64           minus           sprintf         
-bandwidth       int8            mldivide        sqrt            
-ceil            isa             mpower          subsasgn        
-colamd          isbanded        mrdivide        subsref         
-complex         isdiag          mtimes          sum             
-conj            isempty         ne              symamd          
-ctranspose      isequal         nnz             symrcm          
-diag            isfinite        nonzeros        times           
-digraph         isfloat         norm            transpose       
-disp            ishermitian     not             tril            
-display         isinf           numel           triu            
-dmperm          isinteger       nzmax           true            
-double          islogical       ones            uint16          
-eig             ismatrix        or              uint32          
-end             isnan           plus            uint64          
-eps             isnumeric       power           uint8           
-eq              isreal          prod            uminus          
-etree           isscalar        rdivide         uplus           
-false           issparse        real            vertcat         
-find            issymmetric     repmat          xor             
-fix             istril          reshape         zeros           
-flip            istriu          round           
-floor           isvector        sign            
-fprintf         kron            single          
-full            ldivide         size            
-
-Static methods:
-
-apply           emult           issigned        reduce          
-assign          entries         kronecker       select          
-bfs             expand          ktruss          selectopinfo    
-binopinfo       extract         laplacian       semiringinfo    
-build           extracttuples   mis             speye           
-burble          eye             monoidinfo      subassign       
-chunk           finalize        mxm             threads         
-clear           format          nonz            trans           
-compact         incidence       normdiff        tricount        
-descriptorinfo  init            offdiag         type            
-dnn             isbycol         pagerank        unopinfo        
-eadd            isbyrow         prune           vreduce         
-empty           isfull          random          
-
-

Zeros are handled differently

Explicit zeros cannot be automatically dropped from a GraphBLAS matrix, like they are in MATLAB sparse matrices. In a shortest-path problem, for example, an edge A(i,j) that is missing has an infinite weight, (the monoid identity of min(x,y) is +inf). A zero edge weight A(i,j)=0 is very different from an entry that is not present in A. However, if a GraphBLAS matrix is converted into a MATLAB sparse matrix, explicit zeros are dropped, which is the convention for a MATLAB sparse matrix. They can also be dropped from a GraphBLAS matrix using the GrB.select method.

G = GrB (magic (2)) ;
-G (1,1) = 0      % G(1,1) still appears as an explicit entry
-A = double (G)   % but it's dropped when converted to MATLAB sparse
-H = GrB.select ('nonzero', G)  % drops the explicit zeros from G
-fprintf ('nnz (G): %d  nnz (A): %g nnz (H): %g\n', ...
-    nnz (G), nnz (A), nnz (H)) ;
-fprintf ('num entries in G: %d\n', GrB.entries (G)) ;
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  3 nonzeros, 4 entries
-
-    (1,1)    0
-    (2,1)    4
-    (1,2)    3
-    (2,2)    2
-
-A =
-   (2,1)        4
-   (1,2)        3
-   (2,2)        2
-
-H =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  3 nonzeros, 3 entries
-
-    (2,1)    4
-    (1,2)    3
-    (2,2)    2
-
-nnz (G): 3  nnz (A): 3 nnz (H): 3
-num entries in G: 4
-

Displaying contents of a GraphBLAS matrix

Unlike MATLAB, the default is to display just a few entries of a GrB matrix. Here are all 100 entries of a 10-by-10 matrix, using a non-default disp(G,3):

G = GrB (rand (10)) ;
-% display everything:
-disp (G,3)
-
-G =
-
-  10x10 GraphBLAS double matrix, sparse by col:
-  100 nonzeros, 100 entries
-
-    (1,1)    0.0342763
-    (2,1)    0.17802
-    (3,1)    0.887592
-    (4,1)    0.889828
-    (5,1)    0.769149
-    (6,1)    0.00497062
-    (7,1)    0.735693
-    (8,1)    0.488349
-    (9,1)    0.332817
-    (10,1)    0.0273313
-    (1,2)    0.467212
-    (2,2)    0.796714
-    (3,2)    0.849463
-    (4,2)    0.965361
-    (5,2)    0.902248
-    (6,2)    0.0363252
-    (7,2)    0.708068
-    (8,2)    0.322919
-    (9,2)    0.700716
-    (10,2)    0.472957
-    (1,3)    0.204363
-    (2,3)    0.00931977
-    (3,3)    0.565881
-    (4,3)    0.183435
-    (5,3)    0.00843818
-    (6,3)    0.284938
-    (7,3)    0.706156
-    (8,3)    0.909475
-    (9,3)    0.84868
-    (10,3)    0.564605
-    (1,4)    0.075183
-    (2,4)    0.535293
-    (3,4)    0.072324
-    (4,4)    0.515373
-    (5,4)    0.926149
-    (6,4)    0.949252
-    (7,4)    0.0478888
-    (8,4)    0.523767
-    (9,4)    0.167203
-    (10,4)    0.28341
-    (1,5)    0.122669
-    (2,5)    0.441267
-    (3,5)    0.157113
-    (4,5)    0.302479
-    (5,5)    0.758486
-    (6,5)    0.910563
-    (7,5)    0.0246916
-    (8,5)    0.232421
-    (9,5)    0.38018
-    (10,5)    0.677531
-    (1,6)    0.869074
-    (2,6)    0.471459
-    (3,6)    0.624929
-    (4,6)    0.987186
-    (5,6)    0.282885
-    (6,6)    0.843833
-    (7,6)    0.869597
-    (8,6)    0.308209
-    (9,6)    0.201332
-    (10,6)    0.706603
-    (1,7)    0.563222
-    (2,7)    0.575795
-    (3,7)    0.056376
-    (4,7)    0.73412
-    (5,7)    0.608022
-    (6,7)    0.0400164
-    (7,7)    0.540801
-    (8,7)    0.023064
-    (9,7)    0.165682
-    (10,7)    0.250393
-    (1,8)    0.23865
-    (2,8)    0.232033
-    (3,8)    0.303191
-    (4,8)    0.579934
-    (5,8)    0.267751
-    (6,8)    0.916376
-    (7,8)    0.833499
-    (8,8)    0.978692
-    (9,8)    0.734445
-    (10,8)    0.102896
-    (1,9)    0.353059
-    (2,9)    0.738955
-    (3,9)    0.57539
-    (4,9)    0.751433
-    (5,9)    0.93256
-    (6,9)    0.281622
-    (7,9)    0.51302
-    (8,9)    0.24406
-    (9,9)    0.950086
-    (10,9)    0.303638
-    (1,10)    0.563593
-    (2,10)    0.705101
-    (3,10)    0.0604146
-    (4,10)    0.672065
-    (5,10)    0.359793
-    (6,10)    0.62931
-    (7,10)    0.977758
-    (8,10)    0.394328
-    (9,10)    0.765651
-    (10,10)    0.457809
-
-
-

That was disp(G,3), so every entry was printed. It's a little long, so the default is not to print everything.

With the default display (level = 2):

G
-
-G =
-
-  10x10 GraphBLAS double matrix, sparse by col:
-  100 nonzeros, 100 entries
-
-    (1,1)    0.0342763
-    (2,1)    0.17802
-    (3,1)    0.887592
-    (4,1)    0.889828
-    (5,1)    0.769149
-    (6,1)    0.00497062
-    (7,1)    0.735693
-    (8,1)    0.488349
-    (9,1)    0.332817
-    (10,1)    0.0273313
-    (1,2)    0.467212
-    (2,2)    0.796714
-    (3,2)    0.849463
-    (4,2)    0.965361
-    (5,2)    0.902248
-    (6,2)    0.0363252
-    (7,2)    0.708068
-    (8,2)    0.322919
-    (9,2)    0.700716
-    (10,2)    0.472957
-    (1,3)    0.204363
-    (2,3)    0.00931977
-    (3,3)    0.565881
-    (4,3)    0.183435
-    (5,3)    0.00843818
-    (6,3)    0.284938
-    (7,3)    0.706156
-    (8,3)    0.909475
-    (9,3)    0.84868
-    (10,3)    0.564605
-    ...
-
-

That was disp(G,2) or just display(G), which is what is printed by a MATLAB statement that doesn't have a trailing semicolon. With level = 1, disp(G,1) gives just a terse summary:

disp (G,1)
-
-G =
-
-  10x10 GraphBLAS double matrix, sparse by col:
-  100 nonzeros, 100 entries
-
-
-

Storing a matrix by row or by column

MATLAB stores its sparse matrices by column, refered to as 'standard CSC' in SuiteSparse:GraphBLAS. In the CSC (compressed sparse column) format, each column of the matrix is stored as a list of entries, with their value and row index. In the CSR (compressed sparse row) format, each row is stored as a list of values and their column indices. GraphBLAS uses both CSC and CSR, and the two formats can be intermixed arbitrarily. In its C interface, the default format is CSR. However, for better compatibility with MATLAB, this MATLAB interface for SuiteSparse:GraphBLAS uses CSC by default instead.

rng ('default') ;
-GrB.clear ;                      % clear all prior GraphBLAS settings
-fprintf ('the default format is: %s\n', GrB.format) ;
-C = sparse (rand (2))
-G = GrB (C)
-GrB.format (G)
-
the default format is: by col
-C =
-   (1,1)       0.8147
-   (2,1)       0.9058
-   (1,2)       0.1270
-   (2,2)       0.9134
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.814724
-    (2,1)    0.905792
-    (1,2)    0.126987
-    (2,2)    0.913376
-
-ans =
-    'by col'
-

Many graph algorithms work better in CSR format, with matrices stored by row. For example, it is common to use A(i,j) for the edge (i,j), and many graph algorithms need to access the out-adjacencies of nodes, which is the row A(i,;) for node i. If the CSR format is desired, GrB.format ('by row') tells GraphBLAS to create all subsequent matrices in the CSR format. Converting from a MATLAB sparse matrix (in standard CSC format) takes a little more time (requiring a transpose), but subsequent graph algorithms can be faster.

G = GrB (C, 'by row')
-fprintf ('the format of G is:    %s\n', GrB.format (G)) ;
-H = GrB (C)
-fprintf ('the format of H is:    %s\n', GrB.format (H)) ;
-err = norm (H-G,1)
-
-G =
-
-  2x2 GraphBLAS double matrix, sparse by row:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.814724
-    (1,2)    0.126987
-    (2,1)    0.905792
-    (2,2)    0.913376
-
-the format of G is:    by row
-
-H =
-
-  2x2 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.814724
-    (2,1)    0.905792
-    (1,2)    0.126987
-    (2,2)    0.913376
-
-the format of H is:    by col
-err =
-     0
-

Hypersparse matrices

SuiteSparse:GraphBLAS can use two kinds of sparse matrix data structures: standard and hypersparse, for both CSC and CSR formats. In the standard CSC format used in MATLAB, an m-by-n matrix A takes O(n+nnz(A)) space. MATLAB can create huge column vectors, but not huge matrices (when n is huge).

clear all
-[c, huge] = computer ;
-C = sparse (huge, 1)    % MATLAB can create a huge-by-1 sparse column
-try
-    C = sparse (huge, huge)     % but this fails
-catch me
-    error_expected = me
-end
-
C =
-   All zero sparse: 281474976710655x1
-error_expected = 
-  MException with properties:
-
-    identifier: 'MATLAB:array:SizeLimitExceeded'
-       message: 'Requested 281474976710655x281474976710655 (2097152.0GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See <a href="matlab: helpview([docroot '/matlab/helptargets.map'], 'matlab_env_workspace_prefs')">array size limit</a> or preference panel for more information.'
-         cause: {}
-         stack: [4x1 struct]
-    Correction: []
-

In a GraphBLAS hypersparse matrix, an m-by-n matrix A takes only O(nnz(A)) space. The difference can be huge if nnz (A) << n.

clear
-[c, huge] = computer ;
-G = GrB (huge, 1)            % no problem for GraphBLAS
-H = GrB (huge, huge)         % this works in GraphBLAS too
-
-G =
-
-  281474976710655x1 GraphBLAS double matrix, sparse by col:
-  no nonzeros, no entries
-
-
-H =
-
-  281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
-  no nonzeros, no entries
-
-

Operations on huge hypersparse matrices are very fast; no component of the time or space complexity is Omega(n).

I = randperm (huge, 2) ;
-J = randperm (huge, 2) ;
-H (I,J) = magic (2) ;        % add 4 nonzeros to random locations in H
-H (I,I) = 10 * [1 2 ; 3 4] ; % so H^2 is not all zero
-H = H^2 ;                    % square H
-H = (H' * 2) ;               % transpose H and double the entries
-K = pi * spones (H) ;
-H = H + K                    % add pi to each entry in H
-
-H =
-
-  281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
-  8 nonzeros, 8 entries
-
-    (27455183225557,27455183225557)    4403.14
-    (78390279669562,27455183225557)    383.142
-    (153933462881710,27455183225557)    343.142
-    (177993304104065,27455183225557)    3003.14
-    (27455183225557,177993304104065)    2003.14
-    (78390279669562,177993304104065)    183.142
-    (153933462881710,177993304104065)    143.142
-    (177993304104065,177993304104065)    1403.14
-
-

numel uses vpa if the matrix is really huge

e1 = numel (G)               % this is huge, but still a flint
-e2 = numel (H)               % this is huge^2, which needs vpa
-whos e1 e2
-
e1 =
-   2.8147e+14
-e2 =
-79228162514263774643590529025.0
-  Name      Size            Bytes  Class     Attributes
-
-  e1        1x1                 8  double              
-  e2        1x1                 8  sym                 
-
-

All of these matrices take very little memory space:

whos C G H K
-
  Name                    Size                         Bytes  Class    Attributes
-
-  G         281474976710655x1                            989  GrB                
-  H         281474976710655x281474976710655             1308  GrB                
-  K         281474976710655x281474976710655             1308  GrB                
-
-

The mask and accumulator

When not used in overloaded operators or built-in functions, many GraphBLAS methods of the form GrB.method ( ... ) can optionally use a mask and/or an accumulator operator. If the accumulator is '+' in GrB.mxm, for example, then C = C + A*B is computed. The mask acts much like logical indexing in MATLAB. With a logical mask matrix M, C<M>=A*B allows only part of C to be assigned. If M(i,j) is true, then C(i,j) can be modified. If false, then C(i,j) is not modified.

For example, to set all values in C that are greater than 0.5 to 3:

A = rand (3)
-C = GrB.assign (A, A > 0.5, 3) ;     % in GraphBLAS
-C1 = GrB (A) ; C1 (A > .5) = 3       % also in GraphBLAS
-C2 = A      ; C2 (A > .5) = 3       % in MATLAB
-err = norm (C - C1, 1)
-err = norm (C - C2, 1)
-
A =
-    0.9575    0.9706    0.8003
-    0.9649    0.9572    0.1419
-    0.1576    0.4854    0.4218
-
-C1 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)    3
-    (2,1)    3
-    (3,1)    0.157613
-    (1,2)    3
-    (2,2)    3
-    (3,2)    0.485376
-    (1,3)    3
-    (2,3)    0.141886
-    (3,3)    0.421761
-
-C2 =
-    3.0000    3.0000    3.0000
-    3.0000    3.0000    0.1419
-    0.1576    0.4854    0.4218
-err =
-     0
-err =
-     0
-

The descriptor

Most GraphBLAS functions of the form GrB.method ( ... ) take an optional last argument, called the descriptor. It is a MATLAB struct that can modify the computations performed by the method. 'help GrB.descriptorinfo' gives all the details. The following is a short summary of the primary settings:

d.out = 'default' or 'replace', clears C after the accum op is used.

d.mask = 'default' or 'complement', to use M or ~M as the mask matrix; 'structural', or 'structural complement', to use the pattern of M or ~M.

d.in0 = 'default' or 'transpose', to transpose A for C=A*B, C=A+B, etc.

d.in1 = 'default' or 'transpose', to transpose B for C=A*B, C=A+B, etc.

d.kind = 'default', 'GrB', 'sparse', or 'full'; the output of GrB.method.

A = sparse (rand (2)) ;
-B = sparse (rand (2)) ;
-C1 = A'*B ;
-C2 = GrB.mxm ('+.*', A, B, struct ('in0', 'transpose')) ;
-err = norm (C1-C2,1)
-
err =
-     0
-

Integer arithmetic is different in GraphBLAS

MATLAB supports integer arithmetic on its full matrices, using int8, int16, int32, int64, uint8, uint16, uint32, or uint64 data types. None of these integer data types can be used to construct a MATLAB sparse matrix, which can only be double, double complex, or logical. Furthermore, C=A*B is not defined for integer types in MATLAB, except when A and/or B are scalars.

GraphBLAS supports all of those types for its sparse matrices (except for complex, which will be added in the future). All operations are supported, including C=A*B when A or B are any integer type, for all 1,865 semirings (1,040 of which are unique).

However, integer arithmetic differs in GraphBLAS and MATLAB. In MATLAB, integer values saturate if they exceed their maximum value. In GraphBLAS, integer operators act in a modular fashion. The latter is essential when computing C=A*B over a semiring. A saturating integer operator cannot be used as a monoid since it is not associative.

The C API for GraphBLAS allows for the creation of arbitrary user-defined types, so it would be possible to create different binary operators to allow element-wise integer operations to saturate, perhaps:

C = GrB.eadd('+saturate',A,B)
-

This would require an extension to this MATLAB interface.

C = uint8 (magic (3)) ;
-G = GrB (C) ;
-C1 = C * 40
-C2 = G * 40
-C3 = double (G) * 40 ;
-S = double (C1 < 255) ;
-assert (isequal (double (C1).*S, double (C2).*S))
-assert (isequal (nonzeros (C2), double (mod (nonzeros (C3), 256))))
-
C1 =
-  3x3 uint8 matrix
-   255    40   240
-   120   200   255
-   160   255    80
-
-C2 =
-
-  3x3 GraphBLAS uint8_t matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)   64
-    (2,1)   120
-    (3,1)   160
-    (1,2)   40
-    (2,2)   200
-    (3,2)   104
-    (1,3)   240
-    (2,3)   24
-    (3,3)   80
-
-

An example graph algorithm: breadth-first search

The breadth-first search of a graph finds all nodes reachable from the source node, and their level, v. v=GrB.bfs(A,s) or v=bfs_matlab(A,s) compute the same thing, but GrB.bfs uses GraphBLAS matrices and operations, while bfs_matlab uses pure MATLAB operations. v is defined as v(s) = 1 for the source node, v(i) = 2 for nodes adjacent to the source, and so on.

clear all
-rng ('default') ;
-n = 1e5 ;
-A = logical (sprandn (n, n, 1e-3)) ;
-
-tic
-v1 = GrB.bfs (A, 1) ;
-gb_time = toc ;
-
-tic
-v2 = bfs_matlab (A, 1) ;
-matlab_time = toc ;
-
-assert (isequal (double (v1'), v2))
-fprintf ('\nnodes reached: %d of %d\n', nnz (v2), n) ;
-fprintf ('GraphBLAS time: %g sec\n', gb_time) ;
-fprintf ('MATLAB time:    %g sec\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
-nodes reached: 100000 of 100000
-GraphBLAS time: 0.761582 sec
-MATLAB time:    0.472689 sec
-Speedup of GraphBLAS over MATLAB: 0.620667
-

Example graph algorithm: Luby's method in GraphBLAS

The GrB.mis.m function is variant of Luby's randomized algorithm [Luby 1985]. It is a parallel method for finding an maximal independent set of nodes, where no two nodes are adjacent. See the GraphBLAS/@GrB/GrB.mis.m function for details. The graph must be symmetric with a zero-free diagonal, so A is symmetrized first and any diagonal entries are removed.

A = GrB (A) ;
-A = GrB.offdiag (A|A') ;
-
-tic
-s = GrB.mis (A) ;
-toc
-fprintf ('# nodes in the graph: %g\n', size (A,1)) ;
-fprintf ('# edges: : %g\n', GrB.entries (A) / 2) ;
-fprintf ('size of maximal independent set found: %g\n', ...
-    full (double (sum (s)))) ;
-
-% make sure it's independent
-p = find (s) ;
-S = A (p,p) ;
-assert (GrB.entries (S) == 0)
-
-% make sure it's maximal
-notp = find (s == 0) ;
-S = A (notp, p) ;
-deg = GrB.vreduce ('+.int64', S) ;
-assert (logical (all (deg > 0)))
-
Elapsed time is 0.497827 seconds.
-# nodes in the graph: 100000
-# edges: : 9.9899e+06
-size of maximal independent set found: 2811
-

Sparse deep neural network

The 2019 MIT GraphChallenge (see http://graphchallenge.org) is to solve a set of large sparse deep neural network problems. In this demo, the MATLAB reference solution is compared with a solution using GraphBLAS, for a randomly constructed neural network. See the GrB.dnn and dnn_matlab.m functions for details.

clear all
-rng ('default') ;
-nlayers = 16 ;
-nneurons = 4096 ;
-nfeatures = 30000 ;
-fprintf ('# layers:   %d\n', nlayers) ;
-fprintf ('# neurons:  %d\n', nneurons) ;
-fprintf ('# features: %d\n', nfeatures) ;
-
-tic
-Y0 = sprand (nfeatures, nneurons, 0.1) ;
-for layer = 1:nlayers
-    W {layer} = sprand (nneurons, nneurons, 0.01) * 0.2 ;
-    bias {layer} = -0.2 * ones (1, nneurons) ;
-end
-t_setup = toc ;
-fprintf ('construct problem time: %g sec\n', t_setup) ;
-
-% convert the problem from MATLAB to GraphBLAS
-t = tic ;
-[W_gb, bias_gb, Y0_gb] = dnn_mat2gb (W, bias, Y0) ;
-t = toc (t) ;
-fprintf ('setup time: %g sec\n', t) ;
-
# layers:   16
-# neurons:  4096
-# features: 30000
-construct problem time: 6.19643 sec
-setup time: 0.428007 sec
-

Solving the sparse deep neural network problem with GraphbLAS

Please wait ...

tic
-Y1 = GrB.dnn (W_gb, bias_gb, Y0_gb) ;
-gb_time = toc ;
-fprintf ('total time in GraphBLAS: %g sec\n', gb_time) ;
-
total time in GraphBLAS: 10.0564 sec
-

Solving the sparse deep neural network problem with MATLAB

Please wait ...

tic
-Y2 = dnn_matlab (W, bias, Y0) ;
-matlab_time = toc ;
-fprintf ('total time in MATLAB:    %g sec\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time) ;
-
-err = norm (Y1-Y2,1)
-
total time in MATLAB:    85.9198 sec
-Speedup of GraphBLAS over MATLAB: 8.54381
-err =
-     0
-

For objects, GraphBLAS has better colon notation than MATLAB

The MATLAB notation C = A (start:inc:fini) is very handy, and it works great if A is a MATLAB matrix. But for objects like the GraphBLAS matrix, MATLAB starts by creating the explicit index vector I = start:inc:fini. That's fine if the matrix is modest in size, but GraphBLAS can construct huge matrices. The problem is that 1:n cannot be explicitly constructed when n is huge.

The C API for GraphBLAS can represent the colon notation start:inc:fini in an implicit manner, so it can do the indexing without actually forming the explicit list I = start:inc:fini. But there is no access to this method using the MATLAB notation start:inc:fini.

Thus, to compute C = A (start:inc:fini) for very huge matrices, you need to use use a cell array to represent the colon notation, as { start, inc, fini }, instead of start:inc:fini. See 'help GrB.extract' and 'help.gbsubassign' for, for C(I,J)=A. The syntax isn't conventional, but it is far faster than the MATLAB colon notation for objects, and takes far less memory when I is huge.

n = 1e14 ;
-H = GrB (n, n) ;            % a huge empty matrix
-I = [1 1e9 1e12 1e14] ;
-M = magic (4)
-H (I,I) = M ;
-J = {1, 1e13} ;            % represents 1:1e13 colon notation
-C1 = H (J, J)              % computes C1 = H (1:e13,1:1e13)
-c = nonzeros (C1) ;
-m = nonzeros (M (1:3, 1:3)) ;
-assert (isequal (c, m)) ;
-
M =
-    16     2     3    13
-     5    11    10     8
-     9     7     6    12
-     4    14    15     1
-
-C1 =
-
-  10000000000000x10000000000000 GraphBLAS double matrix, hypersparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)    16
-    (1000000000,1)    5
-    (1000000000000,1)    9
-    (1,1000000000)    2
-    (1000000000,1000000000)    11
-    (1000000000000,1000000000)    7
-    (1,1000000000000)    3
-    (1000000000,1000000000000)    10
-    (1000000000000,1000000000000)    6
-
-
try
-    % try to compute the same thing with colon
-    % notation (1:1e13), but this fails:
-    C2 = H (1:1e13, 1:1e13)
-catch me
-    error_expected = me
-end
-
error_expected = 
-  MException with properties:
-
-    identifier: 'MATLAB:array:SizeLimitExceeded'
-       message: 'Requested 10000000000000x1 (74505.8GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See <a href="matlab: helpview([docroot '/matlab/helptargets.map'], 'matlab_env_workspace_prefs')">array size limit</a> or preference panel for more information.'
-         cause: {}
-         stack: [4x1 struct]
-    Correction: []
-

Iterative solvers work as-is

Many built-in functions work with GraphBLAS matrices unmodified.

A = sparse (rand (4)) ;
-b = sparse (rand (4,1)) ;
-x = gmres (A,b)
-norm (A*x-b)
-x = gmres (GrB(A), GrB(b))
-norm (A*x-b)
-
gmres converged at iteration 4 to a solution with relative residual 0.
-x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
-ans =
-   8.6711e-16
-gmres converged at iteration 4 to a solution with relative residual 0.
-x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
-ans =
-   7.2802e-16
-

... even in single precision

x = gmres (GrB(A,'single'), GrB(b,'single'))
-norm (A*x-b)
-
gmres converged at iteration 4 to a solution with relative residual 0.
-x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
-ans =
-   3.5566e-07
-

Both of the following uses of minres (A,b) fail to converge because A is not symmetric, as the method requires. Both failures are correctly reported, and both the MATLAB version and the GraphBLAS version return the same incorrect vector x.

x = minres (A, b)
-x = minres (GrB(A), GrB(b))
-
minres stopped at iteration 4 without converging to the desired tolerance 1e-06
-because the maximum number of iterations was reached.
-The iterate returned (number 4) has relative residual 0.21.
-x =
-    0.2489
-    0.2081
-    0.0700
-    0.3928
-minres stopped at iteration 4 without converging to the desired tolerance 1e-06
-because the maximum number of iterations was reached.
-The iterate returned (number 4) has relative residual 0.21.
-
-x =
-
-  4x1 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    0.248942
-    (2,1)    0.208128
-    (3,1)    0.0699707
-    (4,1)    0.392812
-
-

With a proper symmetric matrix

A = A+A' ;
-x = minres (A, b)
-norm (A*x-b)
-x = minres (GrB(A), GrB(b))
-norm (A*x-b)
-
minres converged at iteration 4 to a solution with relative residual 1.3e-11.
-x =
- -114.0616
-   -1.4211
-  134.8227
-    2.0694
-ans =
-   1.3650e-11
-minres converged at iteration 4 to a solution with relative residual 1.3e-11.
-
-x =
-
-  4x1 GraphBLAS double matrix, sparse by col:
-  4 nonzeros, 4 entries
-
-    (1,1)    -114.062
-    (2,1)    -1.4211
-    (3,1)    134.823
-    (4,1)    2.0694
-
-ans =
-   1.3650e-11
-

Extreme performance differences between GraphBLAS and MATLAB.

The GraphBLAS operations used so far are perhaps 2x to 50x faster than the corresponding MATLAB operations, depending on how many cores your computer has. To run a demo illustrating a 500x or more speedup versus MATLAB, run this demo:

  gbdemo2

It will illustrate an assignment C(I,J)=A that can take under a second in GraphBLAS but several minutes in MATLAB. To make the comparsion even more dramatic, try:

  gbdemo2 (20000)

assuming you have enough memory. The gbdemo2 is not part of this demo since it can take a long time; it tries a range of problem sizes, and each one takes several minutes in MATLAB.

Sparse logical indexing is much, much faster in GraphBLAS

The mask in GraphBLAS acts much like logical indexing in MATLAB, but it is not quite the same. MATLAB logical indexing takes the form:

     C (M) = A (M)

which computes the same thing as the GraphBLAS statement:

     C = GrB.assign (C, M, A)

The GrB.assign statement computes C(M)=A(M), and it is vastly faster than C(M)=A(M), even if the time to convert the GrB matrix back to a MATLAB sparse matrix is included.

GraphBLAS can also compute C (M) = A (M) using overloaded operators for subsref and subsasgn, but C = GrB.assign (C, M, A) is a bit faster.

First, both methods in GraphBLAS (both are very fast):

clear
-n = 4000 ;
-tic
-C = sprand (n, n, 0.1) ;
-A = 100 * sprand (n, n, 0.1) ;
-M = (C > 0.5) ;
-t_setup = toc ;
-fprintf ('nnz(C): %g, nnz(M): %g, nnz(A): %g\n', ...
-    nnz(C), nnz(M), nnz(A)) ;
-fprintf ('\nsetup time:     %g sec\n', t_setup) ;
-
-% include the time to convert C1 from a GraphBLAS
-% matrix to a MATLAB sparse matrix:
-tic
-C1 = GrB.assign (C, M, A) ;
-C1 = double (C1) ;
-gb_time = toc ;
-fprintf ('\nGraphBLAS time: %g sec for GrB.assign\n', gb_time) ;
-
-% now using overloaded operators, also include the time to
-% convert back to a MATLAB sparse matrix, for good measure:
-A2 = GrB (A) ;
-C2 = GrB (C) ;
-tic
-C2 (M) = A2 (M) ;
-C2 = double (C2) ;
-gb_time2 = toc ;
-fprintf ('\nGraphBLAS time: %g sec for C(M)=A(M)\n', gb_time2) ;
-
nnz(C): 1.5226e+06, nnz(M): 761163, nnz(A): 1.52245e+06
-
-setup time:     1.00999 sec
-
-GraphBLAS time: 0.026364 sec for GrB.assign
-
-GraphBLAS time: 0.125608 sec for C(M)=A(M)
-

Please wait, this will take about 10 minutes or so ...

tic
-C (M) = A (M) ;
-matlab_time = toc ;
-
-fprintf ('\nGraphBLAS time: %g sec (GrB.assign)\n', gb_time) ;
-fprintf ('\nGraphBLAS time: %g sec (overloading)\n', gb_time2) ;
-fprintf ('MATLAB time:    %g sec\n', matlab_time) ;
-fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
-    matlab_time / gb_time2) ;
-
-% GraphBLAS computes the exact same result with both methods:
-assert (isequal (C1, C))
-assert (isequal (C2, C))
-C1 - C
-C2 - C
-
-GraphBLAS time: 0.026364 sec (GrB.assign)
-
-GraphBLAS time: 0.125608 sec (overloading)
-MATLAB time:    641.779 sec
-Speedup of GraphBLAS over MATLAB: 5109.38
-ans =
-   All zero sparse: 4000x4000
-ans =
-   All zero sparse: 4000x4000
-

Limitations and their future solutions

The MATLAB interface for SuiteSparse:GraphBLAS is a work-in-progress. It has some limitations, most of which will be resolved over time.

(1) Nonblocking mode:

GraphBLAS has a 'non-blocking' mode, in which operations can be left pending and completed later. SuiteSparse:GraphBLAS uses the non-blocking mode to speed up a sequence of assignment operations, such as C(I,J)=A. However, in its MATLAB interface, this would require a MATLAB mexFunction to modify its inputs. That breaks the MATLAB API standard, so it cannot be safely done. As a result, using GraphBLAS via its MATLAB interface can be slower than when using its C API. This restriction would not be a limitation if GraphBLAS were to be incorporated into MATLAB itself, but there is likely no way to do this in a mexFunction interface to GraphBLAS.

(2) Complex matrices:

GraphBLAS can operate on matrices with arbitrary user-defined types and operators. The only constraint is that the type be a fixed sized typedef that can be copied with the ANSI C memcpy; variable-sized types are not yet supported. However, in this MATLAB interface, SuiteSparse:GraphBLAS has access to only predefined types, operators, and semirings. Complex types and operators will be added to this MATLAB interface in the future. They already appear in the C version of GraphBLAS, with user-defined operators in GraphBLAS/Demo/Source/usercomplex.c.

(3) Integer element-wise operations:

Integer operations in MATLAB saturate, so that uint8(255)+1 is 255. To allow for integer monoids, GraphBLAS uses modular arithmetic instead. This is the only way that C=A*B can be defined for integer semirings. However, saturating integer operators could be added in the future, so that element- wise integer operations on GraphBLAS sparse integer matrices could work just the same as their MATLAB counterparts.

So in the future, you could perhaps write this, for both sparse and dense integer matrices A and B:

     C = GrB.eadd ('+saturate.int8', A, B)

to compute the same thing as C=A+B in MATLAB for its full int8 matrices. Note that MATLAB can do this only for dense integer matrices, since it doesn't support sparse integer matrices.

(4) Faster methods:

Most methods in this MATLAB interface are based on efficient parallel C functions in GraphBLAS itself, and are typically as fast or faster than the equivalent built-in operators and functions in MATLAB.

There are few notable exceptions; these will be addressed in the future. Dense matrices and vectors held as GraphBLAS objects are slower than their MATLAB counterparts. horzcat and vertcat, for [A B] and [A;B] when either A or B are GraphBLAS matrices, are also slow, as illustrated below in the next example.

Other methods that will be faster in the future include bandwidth, istriu, istril, eps, ceil, floor, round, fix, isfinite, isinf, isnan, spfun, and A.^B. These methods are currently implemented in m-files, not in efficient parallel C functions.

Here is an example that illustrates the performance of C = [A B]

clear
-A = sparse (rand (2000)) ;
-B = sparse (rand (2000)) ;
-tic
-C1 = [A B] ;
-matlab_time = toc ;
-
-A = GrB (A) ;
-B = GrB (B) ;
-tic
-C2 = [A B] ;
-gb_time = toc ;
-
-err = norm (C1-C2,1)
-fprintf ('\nMATLAB: %g sec, GraphBLAS: %g sec\n', ...
-    matlab_time, gb_time) ;
-if (gb_time > matlab_time)
-    fprintf ('GraphBLAS is slower by a factor of %g\n', ...
-        gb_time / matlab_time) ;
-end
-
err =
-     0
-
-MATLAB: 0.039108 sec, GraphBLAS: 0.117829 sec
-GraphBLAS is slower by a factor of 3.01291
-

(5) Linear indexing:

If A is an m-by-n 2D MATLAB matrix, with n > 1, A(:) is a column vector of length m*n. The index operation A(i) accesses the ith entry in the vector A(:). This is called linear indexing in MATLAB. It is not yet available for GraphBLAS matrices in this MATLAB interface to GraphBLAS, but it could be added in the future.

(6) Implicit singleton dimension expansion

In MATLAB C=A+B where A is m-by-n and B is a 1-by-n row vector implicitly expands B to a matrix, computing C(i,j)=A(i,j)+B(j). This implicit expansion is not yet suported in GraphBLAS with C=A+B. However, it can be done with C = GrB.mxm ('+.+', A, diag(GrB(B))). That's an nice example of the power of semirings, but it's not immediately obvious, and not as clear a syntax as C=A+B. The GraphBLAS/@GrB/dnn.m function uses this 'plus.plus' semiring to apply the bias to each neuron.

A = magic (3)
-B = 1000:1000:3000
-C1 = A + B
-C2 = GrB.mxm ('+.+', A, diag (GrB (B)))
-err = norm (C1-C2,1)
-
A =
-     8     1     6
-     3     5     7
-     4     9     2
-B =
-        1000        2000        3000
-C1 =
-        1008        2001        3006
-        1003        2005        3007
-        1004        2009        3002
-
-C2 =
-
-  3x3 GraphBLAS double matrix, sparse by col:
-  9 nonzeros, 9 entries
-
-    (1,1)    1008
-    (2,1)    1003
-    (3,1)    1004
-    (1,2)    2001
-    (2,2)    2005
-    (3,2)    2009
-    (1,3)    3006
-    (2,3)    3007
-    (3,3)    3002
-
-err =
-     0
-

GraphBLAS operations

In addition to the overloaded operators (such as C=A*B) and overloaded functions (such as L=tril(A)), GraphBLAS also has methods of the form GrB.method, listed on the next page. Most of them take an optional input matrix Cin, which is the initial value of the matrix C for the expression below, an optional mask matrix M, and an optional accumulator operator.

    C<#M,replace> = accum (C, T)

In the above expression, #M is either empty (no mask), M (with a mask matrix) or ~M (with a complemented mask matrix), as determined by the descriptor. 'replace' can be used to clear C after it is used in accum(C,T) but before it is assigned with C<...> = Z, where Z=accum(C,T). The matrix T is the result of some operation, such as T=A*B for GrB.mxm, or T=op(A,B) for GrB.eadd.

A summary of these GrB.methods is on the next pages.

Methods for the GrB class:

These methods operate on GraphBLAS matrices only, and they overload
-the existing MATLAB functions of the same name.
-
C = GrB (...)           construct a GraphBLAS matrix
-C = sparse (G)          makes a copy of a GrB matrix
-C = full (G, ...)       adds explicit zeros or id values to a GrB matrix
-C = double (G)          cast GrB matrix to MATLAB sparse double matrix
-C = logical (G)         cast GrB matrix to MATLAB sparse logical matrix
-C = complex (G)         cast GrB matrix to MATLAB sparse complex
-C = single (G)          cast GrB matrix to MATLAB full single matrix
-C = int8 (G)            cast GrB matrix to MATLAB full int8 matrix
-C = int16 (G)           cast GrB matrix to MATLAB full int16 matrix
-C = int32 (G)           cast GrB matrix to MATLAB full int32 matrix
-C = int64 (G)           cast GrB matrix to MATLAB full int64 matrix
-C = uint8 (G)           cast GrB matrix to MATLAB full uint8 matrix
-C = uint16 (G)          cast GrB matrix to MATLAB full uint16 matrix
-C = uint32 (G)          cast GrB matrix to MATLAB full uint32 matrix
-C = uint64 (G)          cast GrB matrix to MATLAB full uint64 matrix
-C = cast (G,...)        cast GrB matrix to MATLAB matrix (as above)
-
X = nonzeros (G)        extract all entries from a GrB matrix
-[I,J,X] = find (G)      extract all entries from a GrB matrix
-C = spones (G)          return pattern of GrB matrix
-disp (G, level)         display a GrB matrix G
-display (G)             display a GrB matrix G; same as disp(G,2)
-mn = numel (G)          m*n for an m-by-n GrB matrix G
-e = nnz (G)             number of entries in a GrB matrix G
-e = nzmax (G)           number of entries in a GrB matrix G
-[m n] = size (G)        size of a GrB matrix G
-n = length (G)          length of a GrB vector
-s = isempty (G)         true if any dimension of G is zero
-s = issparse (G)        true for any GrB matrix G
-s = ismatrix (G)        true for any GrB matrix G
-s = isvector (G)        true if m=1 or n=1, for an m-by-n GrB matrix G
-s = iscolumn (G)        true if n=1, for an m-by-n GrB matrix G
-s = isrow (G)           true if m=1, for an m-by-n GrB matrix G
-s = isscalar (G)        true if G is a 1-by-1 GrB matrix
-s = isnumeric (G)       true for any GrB matrix G (even logical)
-s = isfloat (G)         true if GrB matrix is double, single, complex
-s = isreal (G)          true if GrB matrix is not complex
-s = isinteger (G)       true if GrB matrix is int8, int16, ..., uint64
-s = islogical (G)       true if GrB matrix is logical
-s = isa (G, classname)  check if a GrB matrix is of a specific class
-
C = diag (G,k)          diagonal matrices and diagonals of GrB matrix G
-L = tril (G,k)          lower triangular part of GrB matrix G
-U = triu (G,k)          upper triangular part of GrB matrix G
-C = kron (A,B)          Kronecker product
-C = repmat (G, ...)     replicate and tile a GraphBLAS matrix
-C = reshape (G, ...)    reshape a GraphBLAS matrix
-C = abs (G)             absolute value
-C = sign (G)            signum function
-s = istril (G)          true if G is lower triangular
-s = istriu (G)          true if G is upper triangular
-s = isbanded (G,...)    true if G is banded
-s = isdiag (G)          true if G is diagonal
-s = ishermitian (G)     true if G is Hermitian
-s = issymmetric (G)     true if G is symmetric
-[lo,hi] = bandwidth (G) determine the lower & upper bandwidth of G
-C = sum (G, option)     reduce via sum, to vector or scalar
-C = prod (G, option)    reduce via product, to vector or scalar
-s = norm (G, kind)      1-norm or inf-norm of a GrB matrix
-C = max (G, ...)        reduce via max, to vector or scalar
-C = min (G, ...)        reduce via min, to vector or scalar
-C = any (G, ...)        reduce via '|', to vector or scalar
-C = all (G, ...)        reduce via '&', to vector or scalar
-
C = sqrt (G)            element-wise square root
-C = eps (G)             floating-point spacing
-C = ceil (G)            round towards infinity
-C = floor (G)           round towards -infinity
-C = round (G)           round towards nearest
-C = fix (G)             round towards zero
-C = isfinite (G)        test if finite
-C = isinf (G)           test if infinite
-C = isnan (G)           test if NaN
-C = spfun (fun, G)      evaluate a function on the entries of G
-p = amd (G)             approximate minimum degree ordering
-p = colamd (G)          column approximate minimum degree ordering
-p = symamd (G)          approximate minimum degree ordering
-p = symrcm (G)          reverse Cuthill-McKee ordering
-[...] = dmperm (G)      Dulmage-Mendelsohn permutation
-parent = etree (G)      elimination tree
-C = conj (G)            complex conjugate
-C = real (G)            real part of a complex GraphBLAS matrix
-[V, ...] = eig (G,...)  eigenvalues and eigenvectors
-assert (G)              generate an error if G is false
-C = zeros (...,'like',G)   all-zero matrix, same type as G
-C = false (...,'like',G)   all-false logical matrix
-C = ones (...,'like',G)    matrix with all ones, same type as G
-

Operator overloading:

C = plus (A, B)         C = A + B
-C = minus (A, B)        C = A - B
-C = uminus (G)          C = -G
-C = uplus (G)           C = +G
-C = times (A, B)        C = A .* B
-C = mtimes (A, B)       C = A * B
-C = rdivide (A, B)      C = A ./ B
-C = ldivide (A, B)      C = A .\ B
-C = mrdivide (A, B)     C = A / B
-C = mldivide (A, B)     C = A \ B
-C = power (A, B)        C = A .^ B
-C = mpower (A, B)       C = A ^ B
-C = lt (A, B)           C = A < B
-C = gt (A, B)           C = A > B
-C = le (A, B)           C = A <= B
-C = ge (A, B)           C = A >= B
-C = ne (A, B)           C = A ~= B
-C = eq (A, B)           C = A == B
-C = and (A, B)          C = A & B
-C = or (A, B)           C = A | B
-C = not (G)             C = ~G
-C = ctranspose (G)      C = G'
-C = transpose (G)       C = G.'
-C = horzcat (A, B)      C = [A , B]
-C = vertcat (A, B)      C = [A ; B]
-C = subsref (A, I, J)   C = A (I,J) or C = A (M)
-C = subsasgn (A, I, J)  C (I,J) = A
-index = end (A, k, n)   for object indexing, A(1:end,1:end)
-

Static Methods:

The Static Methods for the GrB class can be used on input matrices of
-any kind: GraphBLAS sparse matrices, MATLAB sparse matrices, or
-MATLAB dense matrices, in any combination.  The output matrix Cout is
-a GraphBLAS matrix, by default, but can be optionally returned as a
-MATLAB sparse or dense matrix.  The static methods divide into two
-categories: those that perform basic functions, and the GraphBLAS
-operations that use the mask/accum.
-

GraphBLAS basic functions:

GrB.clear                    clear GraphBLAS workspace and settings
-GrB.descriptorinfo (d)       list properties of a descriptor
-GrB.unopinfo (op, type)      list properties of a unary operator
-GrB.binopinfo (op, type)     list properties of a binary operator
-GrB.monoidinfo (op, type)    list properties of a monoid
-GrB.semiringinfo (s, type)   list properties of a semiring
-t = GrB.threads (t)          set/get # of threads to use in GraphBLAS
-c = GrB.chunk (c)            set/get chunk size to use in GraphBLAS
-b = GrB.burble (b)           set/get burble (diagnostic output)
-result = GrB.entries (G,...) count or query entries in a matrix
-result = GrB.nonz (G,...)    count or query nonzeros in a matrix
-C = GrB.prune (A, id)        prune entries equal to id
-C = GrB.offdiag (A)          prune diagonal entries
-s = GrB.isfull (A)           true if all entries present
-[C,I,J] = GrB.compact (A,id) remove empty rows and columns
-G = GrB.empty (m, n)         return an empty GraphBLAS matrix
-s = GrB.type (A)             get the type of a MATLAB or GrB matrix A
-s = GrB.issigned (type)      true if type is signed
-f = GrB.format (f)           set/get matrix format to use in GraphBLAS
-s = GrB.isbyrow (A)          true if format f A is 'by row'
-s = GrB.isbycol (A)          true if format f A is 'by col'
-C = GrB.expand (scalar, A)   expand a scalar (C = scalar*spones(A))
-C = GrB.eye                  identity matrix of any type
-C = GrB.speye                identity matrix (of type 'double')
-C = GrB.build (I, J, X, m, n, dup, type, desc)
-                             build a GrB matrix from list of entries
-[I,J,X] = GrB.extracttuples (A, desc)
-                             extract all entries from a matrix
-s = GrB.normdiff (A, B, kind)   norm (A-B,kind)
-

GraphBLAS operations with Cout, mask M, and accum.

Cout = GrB.mxm (Cin, M, accum, semiring, A, B, desc)
-                sparse matrix-matrix multiplication over a semiring
-Cout = GrB.select (Cin, M, accum, op, A, b, desc)
-                select a subset of entries from a matrix
-Cout = GrB.assign (Cin, M, accum, A, I, J, desc)
-                sparse matrix assignment, such as C(I,J)=A
-Cout = GrB.subassign (Cin, M, accum, A, I, J, desc)
-                sparse matrix assignment, such as C(I,J)=A
-Cout = GrB.vreduce (Cin, M, accum, op, A, desc)
-                reduce a matrix to a vector
-Cout = GrB.reduce (Cin, accum, op, A, desc)
-                reduce a matrix to a scalar
-Cout = GrB.kronecker (Cin, M, accum, op, A, B, desc)
-                Kronecker product
-Cout = GrB.trans (Cin, M, accum, A, desc)
-                transpose a matrix
-Cout = GrB.eadd (Cin, M, accum, op, A, B, desc)
-                element-wise addition
-Cout = GrB.emult (Cin, M, accum, op, A, B, desc)
-                element-wise multiplication
-Cout = GrB.apply (Cin, M, accum, op, A, desc)
-                apply a unary operator
-Cout = GrB.extract (Cin, M, accum, A, I, J, desc)
-                extract submatrix, like C=A(I,J) in MATLAB
-

GraphBLAS operations (with Cout, Cin arguments) take the following form:

C<#M,replace> = accum (C, operation (A or A', B or B'))
-
C is both an input and output matrix.  In this MATLAB interface to
-GraphBLAS, it is split into Cin (the value of C on input) and Cout
-(the value of C on output).  M is the optional mask matrix, and #M is
-either M or !M depending on whether or not the mask is complemented
-via the desc.mask option.  The replace option is determined by
-desc.out; if present, C is cleared after it is used in the accum
-operation but before the final assignment.  A and/or B may optionally
-be transposed via the descriptor fields desc.in0 and desc.in1,
-respectively.  To select the format of Cout, use desc.format.  See
-GrB.descriptorinfo for more details.
-
accum is optional; if not is not present, then the operation becomes
-C<...> = operation(A,B).  Otherwise, C = C + operation(A,B) is
-computed where '+' is the accum operator.  It acts like a sparse
-matrix addition (see GrB.eadd), in terms of the structure of the
-result C, but any binary operator can be used.
-
The mask M acts like MATLAB logical indexing.  If M(i,j)=1 then
-C(i,j) can be modified; if zero, it cannot be modified by the
-operation.
-

Static Methods for graph algorithms:

r = GrB.pagerank (A, opts) ;            % PageRank of a matrix
-C = GrB.ktruss (A, k, check) ;          % k-truss
-s = GrB.tricount (A, check) ;           % triangle count
-L = GrB.laplacian (A, type, check) ;    % Laplacian graph
-C = GrB.incidence (A, ...) ;            % incidence matrix
-[v, parent] = GrB.bfs (A, s, ...) ;     % breadth-first search
-iset = GrB.mis (A, check) ;             % maximal independent set
-Y = GrB.dnn (W, bias, Y0) ;             % deep neural network
-
More graph algorithms will be added in the future.
-

Thanks for watching!

Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis See also sparse, doc sparse, and https://twitter.com/DocSparse

diff --git a/GraphBLAS/demo/html/Dell_Windows10/README.txt b/GraphBLAS/demo/html/Dell_Windows10/README.txt index ee47ea8ce5..a287624b4c 100644 --- a/GraphBLAS/demo/html/Dell_Windows10/README.txt +++ b/GraphBLAS/demo/html/Dell_Windows10/README.txt @@ -4,5 +4,4 @@ RAM: 32GB GPU: AMD Radeon R7 250 MATLAB R2019b Microsoft Visual Studio 2019 -GraphBLAS v3.2.2 diff --git a/GraphBLAS/demo/html/Dell_Windows10/graphblas_demo.html b/GraphBLAS/demo/html/Dell_Windows10/graphblas_demo.html index 7bf8d12a41..96b663d73c 100644 --- a/GraphBLAS/demo/html/Dell_Windows10/graphblas_demo.html +++ b/GraphBLAS/demo/html/Dell_Windows10/graphblas_demo.html @@ -6,7 +6,7 @@ GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS is a library for creating graph algorithms based on sparse linear algebraic operations over semirings. Visit http://graphblas.org for more details and resources. See also the SuiteSparse:GraphBLAS User Guide in this package.

SuiteSparse:GraphBLAS, (c) 2017-2020, Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis

Contents

GraphBLAS: faster and more general sparse matrices for MATLAB

GraphBLAS is not only useful for creating graph algorithms; it also supports a wide range of sparse matrix data types and operations. MATLAB can compute C=A*B with just two semirings: 'plus.times.double' and 'plus.times.complex' for complex matrices. GraphBLAS has 1,040 unique built-in semirings, such as 'max.plus' (https://en.wikipedia.org/wiki/Tropical_semiring). These semirings can be used to construct a wide variety of graph algorithms, based on operations on sparse adjacency matrices.

GraphBLAS supports sparse double and single precision matrices, logical, and sparse integer matrices: int8, int16, int32, int64, uint8, uint16, uint32, and uint64. Complex matrices will be added in the future.

clear
+  

GraphBLAS: graph algorithms in the language of linear algebra

GraphBLAS is a library for creating graph algorithms based on sparse linear algebraic operations over semirings. Visit http://graphblas.org for more details and resources. See also the SuiteSparse:GraphBLAS User Guide in this package.

SuiteSparse:GraphBLAS, (c) 2017-2020, Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis

Contents

GraphBLAS: faster and more general sparse matrices for MATLAB

GraphBLAS is not only useful for creating graph algorithms; it also supports a wide range of sparse matrix data types and operations. MATLAB can compute C=A*B with just two semirings: 'plus.times.double' and 'plus.times.complex' for complex matrices. GraphBLAS has 1,473 unique built-in semirings, such as 'max.plus' (https://en.wikipedia.org/wiki/Tropical_semiring). These semirings can be used to construct a wide variety of graph algorithms, based on operations on sparse adjacency matrices.

MATLAB and GraphBLAS both provide sparse matrices of type double, logical, and double complex. GraphBLAS adds sparse matrices of type: single, int8, int16, int32, int64, uint8, uint16, uint32, uint64, and single complex (with MATLAB matrices, these types can only be held in full matrices).

clear
 GrB.clear
 format compact
 rng ('default') ;
@@ -82,12 +82,13 @@
     (2,1)    90.5792
     (1,2)    12.6987
     (2,2)    91.3376
+
 

Sparse integer matrices

Here's an int8 version of the same matrix:

S = int8 (G)            % convert G to a full MATLAB int8 matrix
 G = GrB (X, 'int8')      % a GraphBLAS sparse int8 matrix
 
S =
   2×2 int8 matrix
-   81   12
-   90   91
+   81   13
+   91   91
 
 G =
 
@@ -95,9 +96,10 @@
   4 nonzeros, 4 entries
 
     (1,1)   81
-    (2,1)   90
-    (1,2)   12
+    (2,1)   91
+    (1,2)   13
     (2,2)   91
+
 

Sparse single-precision matrices

Matrix operations in GraphBLAS are typically as fast, or faster than MATLAB. Here's an unfair comparison: computing X^2 with MATLAB in double precision and with GraphBLAS in single precision. You would naturally expect GraphBLAS to be faster.

Please wait ...

n = 1e5 ;
 X = spdiags (rand (n, 201), -100:100, n, n) ;
 G = GrB (X, 'single') ;
@@ -112,17 +114,17 @@
 fprintf ('Speedup of GraphBLAS over MATLAB: %g\n', ...
     matlab_time / gb_time) ;
 
-GraphBLAS time: 1.5058 sec (in single)
-MATLAB time:    5.78542 sec (in double)
-Speedup of GraphBLAS over MATLAB: 3.84209
+GraphBLAS time: 1.48328 sec (in single)
+MATLAB time:    5.8599 sec (in double)
+Speedup of GraphBLAS over MATLAB: 3.95062
 

Mixing MATLAB and GraphBLAS matrices

The error in the last computation is about eps('single') since GraphBLAS did its computation in single precision, while MATLAB used double precision. MATLAB and GraphBLAS matrices can be easily combined, as in X2-G2. The sparse single precision matrices take less memory space.

err = norm (X2 - G2, 1) / norm (X2,1)
 eps ('single')
 whos G G2 X X2
 
err =
-   1.5049e-07
+      1.50487018943138e-07
 ans =
   single
-  1.1921e-07
+    1.192093e-07
   Name           Size                    Bytes  Class     Attributes
 
   G         100000x100000            241879764  GrB                 
@@ -142,10 +144,10 @@
 
err =
      0
 
-GraphBLAS time: 1.70125 sec (in double)
-MATLAB time:    5.78542 sec (in double)
-Speedup of GraphBLAS over MATLAB: 3.40068
-

A wide range of semirings

MATLAB can only compute C=A*B using the standard '+.*.double' and '+.*.complex' semirings. A semiring is defined in terms of a string, 'add.mult.type', where 'add' is a monoid that takes the place of the additive operator, 'mult' is the multiplicative operator, and 'type' is the data type for the two inputs to the mult operator (the type defaults to the type of A for C=A*B).

In the standard semiring, C=A*B is defined as:

C(i,j) = sum (A(i,:).' .* B(:,j))
+GraphBLAS time: 1.80984 sec (in double)
+MATLAB time:    5.8599 sec (in double)
+Speedup of GraphBLAS over MATLAB: 3.23781
+

A wide range of semirings

MATLAB can only compute C=A*B using the standard '+.*.double' and '+.*.complex' semirings. A semiring is defined in terms of a string, 'add.mult.type', where 'add' is a monoid that takes the place of the additive operator, 'mult' is the multiplicative operator, and 'type' is the data type for the two inputs to the mult operator.

In the standard semiring, C=A*B is defined as:

C(i,j) = sum (A(i,:).' .* B(:,j))
 

using 'plus' as the monoid and 'times' as the multiplicative operator. But in a more general semiring, 'sum' can be any monoid, which is an associative and commutative operator that has an identity value. For example, in the 'max.plus' tropical algebra, C(i,j) for C=A*B is defined as:

C(i,j) = max (A(i,:).' + B(:,j))
 

This can be computed in GraphBLAS with:

C = GrB.mxm ('max.+', A, B)
 
n = 3 ;
@@ -161,7 +163,7 @@
 fprintf ('\nerr = norm (C-C2,1) = %g\n', norm (C-C2,1)) ;
 
 err = norm (C-C2,1) = 0
-

The max.plus tropical semiring

Here are details of the "max.plus" tropical semiring. The identity value is -inf since max(x,-inf) = max (-inf,x) = -inf for any x.

GrB.semiringinfo ('max.+.double') ;
+

The max.plus tropical semiring

Here are details of the "max.plus" tropical semiring. The identity value is -inf since max(x,-inf) = max (-inf,x) = x for any x. The identity for the conventional "plus.times" semiring is zero, since x+0 = 0+x = x for any x.

GrB.semiringinfo ('max.+.double') ;
 
     GraphBLAS Semiring: max.+.double (built-in)
     GraphBLAS Monoid: semiring->add (built-in)
@@ -169,7 +171,7 @@
     GraphBLAS type: ztype double size: 8
     GraphBLAS type: xtype double size: 8
     GraphBLAS type: ytype double size: 8
-    identity: [    -inf ] terminal: [    inf ]
+    identity: [    -Inf ] terminal: [    Inf ]
 
     GraphBLAS BinaryOp: semiring->multiply (built-in) z=plus(x,y)
     GraphBLAS type: ztype double size: 8
@@ -244,6 +246,7 @@
     (1,3)   1
     (2,3)   1
     (3,3)   1
+
 

Note that C1 is a MATLAB sparse double matrix, and contains non-binary values. C2 is a GraphBLAS logical matrix.

whos
 GrB.type (C2)
 
  Name      Size            Bytes  Class      Attributes
@@ -255,51 +258,47 @@
 
 ans =
     'logical'
-

GraphBLAS operators, monoids, and semirings

The C interface for SuiteSparse:GraphBLAS allows for arbitrary types and operators to be constructed. However, the MATLAB interface to SuiteSparse:GraphBLAS is restricted to pre-defined types and operators: a mere 11 types, 66 unary operators, 275 binary operators, 44 monoids, 16 select operators, and 1,865 semirings (1,040 of which are unique, since some binary operators are equivalent: 'min.logical' and '&.logical' are the same thing, for example). The complex type and its binary operators, monoids, and semirings will be added in the near future.

That gives you a lot of tools to create all kinds of interesting graph algorithms. For example:

GrB.bfs    % breadth-first search
+

GraphBLAS operators, monoids, and semirings

The C interface for SuiteSparse:GraphBLAS allows for arbitrary types and operators to be constructed. However, the MATLAB interface to SuiteSparse:GraphBLAS is restricted to pre-defined types and operators: a mere 13 types, 204 unary operators, 385 binary operators, 77 monoids, 16 select operators, and 2,438 semirings (1,473 of which are unique, since some binary operators are equivalent: 'min.logical' and '&.logical' are the same thing, for example).

That gives you a lot of tools to create all kinds of interesting graph algorithms. For example:

GrB.bfs    % breadth-first search
 GrB.dnn    % sparse deep neural network (http://graphchallenge.org)
 GrB.mis    % maximal independent set
-

See 'help GrB.binopinfo' for a list of the binary operators, and 'help GrB.monoidinfo' for the ones that can be used as the additive monoid in a semiring.

help GrB.binopinfo
+

See 'help GrB.binopinfo' for a list of the binary operators, and 'help GrB.monoidinfo' for the ones that can be used as the additive monoid in a semiring. 'help GrB.unopinfo' lists the unary operators.

help GrB.binopinfo
 
 GRB.BINOPINFO list the details of a GraphBLAS binary operator.
  
-  Usage
- 
     GrB.binopinfo
     GrB.binopinfo (op)
-    GrB.binopinfo (op, type)
+    GrB.binopinfo (op, optype)
  
-  For GrB.binopinfo(op), the op must be a string of the form
-  'op.type', where 'op' is listed below.  The second usage allows the
-  type to be omitted from the first argument, as just 'op'.  This is
-  valid for all GraphBLAS operations, since the type defaults to the
-  type of the input matrices.  However, GrB.binopinfo does not have a
-  default type and thus one must be provided, either in the op as
-  GrB.binopinfo ('+.double'), or in the second argument, GrB.binopinfo
-  ('+', 'double').
+  Binary operators are defined by a string of the form 'op.optype', or
+  just 'op', where the optype is inferred from the operands.  Valid
+  optypes are 'logical', 'int8', 'int16', 'int32', 'int64', 'uint8',
+  'uint16', 'uint32', 'uint64', 'single', 'double', 'single complex',
+  'double complex' (the latter can be written as simply 'complex').
  
-  The MATLAB interface to GraphBLAS provides for 27 different binary
-  operators, each of which may be used with any of the 11 types, for
-  a total of 27*11 = 297 valid binary operators.  Binary operators
-  are defined by a string of the form 'op.type', or just 'op'.  In
-  the latter case, the type defaults to the type of the matrix inputs
-  to the GraphBLAS operation.
+  For GrB.binopinfo (op), the op must be a string of the form 'op.optype',
+  where 'op' is listed below.  The second usage allows the optype to be
+  omitted from the first argument, as just 'op'.  This is valid for all
+  GraphBLAS operations, since the optype can be determined from the
+  operands (see Typecasting, below).  However, GrB.binopinfo does not have
+  any operands and thus the optype must be provided, either in the op as
+  GrB.binopinfo ('+.double'), or in the second argument as
+  GrB.binopinfo ('+', 'double').
  
-  The 6 comparator operators come in two flavors.  For the is*
-  operators, the result has the same type as the inputs, x and y,
-  with 1 for true and 0 for false.  For example isgt.double (pi, 3.0)
-  is the double value 1.0.  For the second set of 6 operators (eq,
-  ne, gt, lt, ge, le), the result is always logical (true or false).
-  In a semiring, the type of the add monoid must exactly match the
-  type of the output of the multiply operator, and thus
-  'plus.iseq.double' is valid (counting how many terms are equal).
-  The 'plus.eq.double' semiring is valid, but not the same semiring
-  since the 'plus' of 'plus.eq.double' has a logical type and is thus
-  equivalent to 'or.eq.double'.   The 'or.eq' is true if any terms
-  are equal and false otherwise (it does not count the number of
-  terms that are equal).
+  The 6 comparator operators come in two flavors.  For the is* operators,
+  the result has the same type as the inputs, x and y, with 1 for true and
+  0 for false.  For example isgt.double (pi, 3.0) is the double value 1.0.
+  For the second set of 6 operators (eq, ne, gt, lt, ge, le), the result
+  is always logical (true or false).  In a semiring, the optype of the add
+  monoid must exactly match the type of the output of the multiply
+  operator, and thus 'plus.iseq.double' is valid (counting how many terms
+  are equal).  The 'plus.eq.double' semiring is valid, but not the same
+  semiring since the 'plus' of 'plus.eq.double' has a logical type and is
+  thus equivalent to 'or.eq.double'.   The 'or.eq' is true if any terms
+  are equal and false otherwise (it does not count the number of terms
+  that are equal).
  
-  The following binary operators are available.  Many have equivalent
-  synonyms, so that '1st' and 'first' both define the first(x,y) = x
-  operator.
+  The following binary operators are available for most types.  Many have
+  equivalent synonyms, so that '1st' and 'first' both define the
+  first(x,y) = x operator.
  
     operator name(s) f(x,y)         |   operator names(s) f(x,y)
     ---------------- ------         |   ----------------- ------
@@ -315,62 +314,196 @@
     \   rdiv         y/x            |   <   lt           x < y
     |   || or  lor   x | y          |   >=  ge           x >= y
     &   && and land  x & y          |   <=  le           x <= y
-    xor lxor         xor(x,y)       |
-    pair             1              |   any              x, or y
+    xor lxor         xor(x,y)       |   .^  pow          x .^ y
+    pair             1              |   any              pick x or y
  
-  The three logical operators, lor, land, and lxor, also come in 11
-  types.  z = lor.double (x,y) tests the condition (x~=0) || (y~=0),
+  Comparators (*lt, *gt, *le, *ge) and min/max are not available for
+  complex types.
+ 
+  All of the above operators are defined for logical operands, but many
+  are redundant. 'min.logical' is the same as 'and.logical', for example.
+  Most of the logical operators have aliases: ('lor', 'or', '|') are the
+  same, as are ('lxnor', 'xnor', 'eq', '==') for logical types.
+ 
+  The three logical operators, lor, land, and lxor, can be used with any
+  real types.  z = lor.double (x,y) tests the condition (x~=0) || (y~=0),
   and returns the double value 1.0 if true, or 0.0 if false.
  
+  The following operators are avaiable for single and double (real); their
+  definitions are identical to the ANSI C11 versions of these functions:
+  atan2, hypot, fmod, remainder, copysign, ldxep (also called 'pow2').
+  All produce the same type as the input, on output.
+ 
+  z = cmplx(x,y) can be computed for x and y as single and double; z is
+  single complex or double complex, respectively.
+ 
+  The following bitwise operators are available for any signed or
+  unsigned integer types:  bitor, bitand, bitxor, bitxnor, bitget, bitset,
+  bitclr, and bitshift.
+ 
+  Typecasting:  If the optype is omitted from the string (for example,
+  GrB.eadd (A, '+', B) or simply C = A+B), then the optype is inferred
+  from the type of A and B.  See 'help GrB.optype' for details.
+ 
   Example:
  
     % valid binary operators
-    GrB.binopinfo ('+.double') ;
+    GrB.binopinfo ('+.double') ;    % also a valid unary operator
     GrB.binopinfo ('1st.int32') ;
+    GrB.binopinfo ('cmplx.single') ;
+    GrB.binopinfo ('pow2.double') ; % also a valid unary operator
+    GrB.unopinfo  ('pow2.double') ;
  
     % invalid binary operator (an error; this is a unary op):
     GrB.binopinfo ('abs.double') ;
  
   See also GrB.descriptorinfo, GrB.monoidinfo, GrB.selectopinfo,
-  GrB.semiringinfo, GrB.unopinfo.
+  GrB.semiringinfo, GrB.unopinfo, GrB.optype.
 
 
help GrB.monoidinfo
 
 GRB.MONOIDINFO list the details of a GraphBLAS monoid.
  
-  Usage
- 
     GrB.monoidinfo
     GrB.monoidinfo (monoid)
     GrB.monoidinfo (monoid, type)
  
-  For GrB.monoidinfo(op), the op must be a string of the form
-  'op.type', where 'op' is listed below.  The second usage allows the
-  type to be omitted from the first argument, as just 'op'.  This is
-  valid for all GraphBLAS operations, since the type defaults to the
-  type of the input matrices.  However, GrB.monoidinfo does not have a
-  default type and thus one must be provided, either in the op as
-  GrB.monoidinfo ('+.double'), or in the second argument,
-  GrB.monoidinfo ('+', 'double').
+  For GrB.monoidinfo(op), the op must be a string of the form 'op.type',
+  where 'op' is listed below.  The second usage allows the type to be
+  omitted from the first argument, as just 'op'.  This is valid for all
+  GraphBLAS operations, since the type defaults to the type of the input
+  matrices.  However, GrB.monoidinfo does not have a default type and thus
+  one must be provided, either in the op as GrB.monoidinfo ('+.double'), or
+  in the second argument, GrB.monoidinfo ('+', 'double').
  
-  The MATLAB interface to GraphBLAS provides for 44 different
-  monoids.  The valid monoids are: '+', '*', 'max', and 'min' for all
-  but the 'logical' type, and '|', '&', 'xor', and 'eq' for the
-  'logical' type.
+  A monoid is any binary operator z=f(x,y) that is commutative and
+  associative, with an identity value o so that f(x,o)=f(o,x)=o.  The types
+  of z, x, and y must all be identical.  For example, the plus.double
+  operator is f(x,y)=x+y, with zero as the identity value (x+0 = 0+x = x).
+  The times monoid has an identity value of 1 (since x*1 = 1*x = x).  The
+  identity of min.double is -inf.
+ 
+  The valid monoids for real non-logical types are:
+        '+', '*', 'max', 'min', 'any'
+  For the 'logical' type:
+        '|', '&', 'xor', 'eq', 'any'
+  For complex types:
+        '+', '*', 'any'
+  For integer types (signed and unsigned):
+        'bitor', 'bitand', 'bitxor', 'bitxnor'
+ 
+  Some monoids have synonyms; see 'help GrB.binopinfo' for details.
  
   Example:
  
     % valid monoids
     GrB.monoidinfo ('+.double') ;
     GrB.monoidinfo ('*.int32') ;
+    GrB.monoidinfo ('min.double') ;
  
     % invalid monoids
     GrB.monoidinfo ('1st.int32') ;
     GrB.monoidinfo ('abs.double') ;
+    GrB.monoidinfo ('min.complex') ;
  
-  See also GrB.binopinfo, GrB.descriptorinfo, % GrB.selectopinfo,
+  See also GrB.binopinfo, GrB.descriptorinfo, GrB.selectopinfo,
   GrB.semiringinfo, GrB.unopinfo.
 
-

Element-wise operations

Binary operators can be used in element-wise matrix operations, like C=A+B and C=A.*B. For the matrix addition C=A+B, the pattern of C is the set union of A and B, and the '+' operator is applied for entries in the intersection. Entries in A but not B, or in B but not A, are assigned to C without using the operator. The '+' operator is used for C=A+B but any operator can be used with GrB.eadd.

A = GrB (sprand (3, 3, 0.5)) ;
+
help GrB.unopinfo
+
 GRB.UNOPINFO list the details of a GraphBLAS unary operator.
+ 
+    GrB.unopinfo
+    GrB.unopinfo (op)
+    GrB.unopinfo (op, type)
+ 
+  For GrB.unopinfo(op), the op must be a string of the form 'op.type',
+  where 'op' is listed below.  The second usage allows the type to be
+  omitted from the first argument, as just 'op'.  This is valid for all
+  GraphBLAS operations, since the type defaults to the type of the input
+  matrix.  However, GrB.unopinfo does not have a default type and thus one
+  must be provided, either in the op as GrB.unopinfo ('abs.double'), or in
+  the second argument, GrB.unopinfo ('abs', 'double').
+ 
+  The functions z=f(x) are listed below.  Unless otherwise specified,
+  z and x have the same type.  Some functions have synonyms, as listed.
+ 
+  For all 13 types:
+    identity    z = x       also '+', 'uplus'
+    ainv        z = -x      additive inverse, also '-', 'negate', 'uminus'
+    minv        z = 1/x     multiplicative inverse
+    one         z = 1       does not depend on x, also '1'
+    abs         z = |x|     'abs.complex' returns a real result
+ 
+  For all 11 real types:
+    lnot        z = ~(x ~= 0)   logical negation (z is 1 or 0, with the
+                                same type as x), also '~', 'not'.
+ 
+  For 4 floating-point types (real & complex)x(single & double):
+    sqrt        z = sqrt (x)    square root
+    log         z = log (x)     base-e logarithm
+    log2        z = log2 (x)    base-2 logarithm
+    log10       z = log10 (x)   base-10 logarithm
+    log1p       z = log1p (x)   log (x-1), base-e
+    exp         z = exp (x)     base-e exponential, e^x
+    pow2        z = pow2 (x)    base-2 exponential, 2^x
+    expm1       z = exp1m (x)   e^x-1
+    sin         z = sin (x)     sine
+    cos         z = cos (x)     cosine
+    tan         z = tan (x)     tangent
+    acos        z = acos (x)    arc cosine
+    asin        z = asin (x)    arc sine
+    atan        z = atan (x)    arc tangent
+    sinh        z = sinh (x)    hyperbolic sine
+    cosh        z = cosh (x)    hyperbolic cosine
+    tanh        z = tanh (x)    hyperbolic tangent
+    asinh       z = asinh (x)   inverse hyperbolic sine
+    acosh       z = acosh (x)   inverse hyperbolic cosine
+    atanh       z = atanh (x)   inverse hyperbolic tangent
+    signum      z = signum (x)  signum function, also 'sign'
+    ceil        z = ceil (x)    ceiling
+    floor       z = floor (x)   floor
+    round       z = round (x)   round to nearest
+    trunc       z = trunc (x)   truncate, also 'fix'
+ 
+  For 'single complex' and 'double complex' only:
+    creal       z = real (x)    real part of x (z is real), also 'real'
+    cimag       z = imag (x)    imag. part of x (z is real), also 'imag'
+    carg        z = carg (x)    phase angle (z is real), also 'angle'
+    conj        z = conj (x)    complex conjugate (z is complex)
+ 
+  For all 4 floating-point types (result is logical):
+    isinf       z = isinf (x)       true if x is +Inf or -Inf
+    isnan       z = isnan (x)       true if x is NaN
+    isfinite    z = isfinite (x)    true if x is finite
+ 
+  For single and double (result same type as input):
+    lgamma      z = lgamma (x)  log of gamma function, also 'gammaln'
+    tgamma      z = tgamma (x)  gamma function, also 'gamma'
+    erf         z = erf (x)     error function
+    erfc        z = erfc (x)    complementary error function
+    frexpx      z = frexpx (x)  mantissa from ANSI C11 frexp function
+    frexpe      z = frexpe (x)  exponent from ANSI C11 frexp function
+                                The MATLAB [f,e]=log2(x) returns
+                                f = frexpx (x) and e = frexpe (x).
+ 
+  For integer types only (result is same type as input):
+    bitcmp      z = ~(x)        bitwise complement, also 'bitnot'
+ 
+  Example:
+ 
+    % valid unary operators
+    GrB.unopinfo ('+.double') ;     % also a valid binary operator
+    GrB.unopinfo ('abs.double') ;
+    GrB.unopinfo ('not.int32') ;
+    GrB.unopinfo ('pow2.double') ;  % also a valid binary operator
+    GrB.binopinfo ('pow2.double') ;
+ 
+    % invalid unary operator (generates an error; this is a binary op):
+    GrB.unopinfo ('*.double') ;
+ 
+  See also GrB.binopinfo, GrB.descriptorinfo, GrB.monoidinfo,
+  GrB.selectopinfo, GrB.semiringinfo.
+
+

Element-wise operations

Binary operators can be used in element-wise matrix operations, like C=A+B and C=A.*B. For the matrix addition C=A+B, the pattern of C is the set union of A and B, and the '+' operator is applied for entries in the intersection. Entries in A but not B, or in B but not A, are assigned to C without using the operator. The '+' operator is used for C=A+B but any operator can be used with GrB.eadd.

A = GrB (sprand (3, 3, 0.5)) ;
 B = GrB (sprand (3, 3, 0.5)) ;
 C1 = A + B
 C2 = GrB.eadd ('+', A, B)
@@ -389,6 +522,7 @@
     (2,3)    0.248635
     (3,3)    0.104226
 
+
 C2 =
 
   3x3 GraphBLAS double matrix, sparse by col:
@@ -401,9 +535,10 @@
     (3,2)    0.566879
     (2,3)    0.248635
     (3,3)    0.104226
+
 err =
      0
-

Subtracting two matrices

A-B and GrB.eadd ('-', A, B) are not the same thing, since the '-' operator is not applied to an entry that is in B but not A.

C1 = A-B
+

Subtracting two matrices

A-B and GrB.eadd ('-', A, B) are not the same thing, since the '-' operator is not applied to an entry that is in B but not A.

C1 = A-B
 C2 = GrB.eadd ('-', A, B)
 
 C1 =
@@ -419,6 +554,7 @@
     (2,3)    0.248635
     (3,3)    0.104226
 
+
 C2 =
 
   3x3 GraphBLAS double matrix, sparse by col:
@@ -431,6 +567,7 @@
     (3,2)    0.566879
     (2,3)    0.248635
     (3,3)    0.104226
+
 

But these give the same result

C1 = A-B
 C2 = GrB.eadd ('+', A, GrB.apply ('-', B))
 err = norm (C1-C2,1)
@@ -448,6 +585,7 @@
     (2,3)    0.248635
     (3,3)    0.104226
 
+
 C2 =
 
   3x3 GraphBLAS double matrix, sparse by col:
@@ -460,9 +598,10 @@
     (3,2)    0.566879
     (2,3)    0.248635
     (3,3)    0.104226
+
 err =
      0
-

Element-wise 'multiplication'

For C = A.*B, the result C is the set intersection of the pattern of A and B. The operator is applied to entries in both A and B. Entries in A but not B, or B but not A, do not appear in the result C.

C1 = A.*B
+

Element-wise 'multiplication'

For C = A.*B, the result C is the set intersection of the pattern of A and B. The operator is applied to entries in both A and B. Entries in A but not B, or B but not A, do not appear in the result C.

C1 = A.*B
 C2 = GrB.emult ('*', A, B)
 C3 = double (A) .* double (B)
 
@@ -473,14 +612,16 @@
 
     (1,2)    0.518474
 
+
 C2 =
 
   3x3 GraphBLAS double matrix, sparse by col:
   1 nonzero, 1 entry
 
     (1,2)    0.518474
+
 C3 =
-   (1,2)       0.5185
+   (1,2)            0.518474419030681
 

Just as in GrB.eadd, any operator can be used in GrB.emult:

A
 B
 C2 = GrB.emult ('max', A, B)
@@ -495,6 +636,7 @@
     (2,3)    0.248635
     (3,3)    0.104226
 
+
 B =
 
   3x3 GraphBLAS double matrix, sparse by col:
@@ -505,15 +647,17 @@
     (1,2)    0.906378
     (2,2)    0.146938
 
+
 C2 =
 
   3x3 GraphBLAS double matrix, sparse by col:
   1 nonzero, 1 entry
 
     (1,2)    0.906378
-

Overloaded operators

The following operators all work as you would expect for any matrix. The matrices A and B can be GraphBLAS matrices, or MATLAB sparse or dense matrices, in any combination, or scalars where appropriate:

  A+B   A-B  A*B   A.*B  A./B  A.\B  A.^b   A/b   C=A(I,J)
-  -A    +A   ~A    A'    A.'   A&B   A|B    b\A   C(I,J)=A
-  A~=B  A>B  A==B  A<=B  A>=B  A<B   [A,B]  [A;B]
+
+

Overloaded operators

The following operators all work as you would expect for any matrix. The matrices A and B can be GraphBLAS matrices, or MATLAB sparse or dense matrices, in any combination, or scalars where appropriate, The matrix M is logical (MATLAB or GraphBLAS):

  A+B   A-B  A*B   A.*B  A./B  A.\B  A.^b   A/b   C=A(I,J)  C(M)=A
+  -A    +A   ~A    A'    A.'   A&B   A|B    b\A   C(I,J)=A  C=A(M)
+  A~=B  A>B  A==B  A<=B  A>=B  A<B   [A,B]  [A;B] C(A)
   A(1:end,1:end)

For A^b, b must be a non-negative integer.

C1 = [A B] ;
 C2 = [double(A) double(B)] ;
 assert (isequal (double (C1), C2))
@@ -532,6 +676,7 @@
     (1,3)    0.142227
     (2,3)    0.0259144
     (3,3)    0.151809
+
 err =
      0
 
C1 = A (1:2,2:end)
@@ -546,7 +691,8 @@
 
     (1,1)    0.572029
     (2,2)    0.248635
-

Overloaded functions

Many MATLAB built-in functions can be used with GraphBLAS matrices:

A few differences with the built-in functions:

S = sparse (G)        % makes a copy of a GrB matrix
+
+

Overloaded functions

Many MATLAB built-in functions can be used with GraphBLAS matrices:

A few differences with the built-in functions:

S = sparse (G)        % makes a copy of a GrB matrix
 F = full (G)          % adds explicit zeros, so numel(F)==nnz(F)
 F = full (G,type,id)  % adds explicit identity values to a GrB matrix
 disp (G, level)       % display a GrB matrix G; level=2 is the default.
@@ -554,55 +700,67 @@
 
 Methods for class GrB:
 
-GrB             ge              le              sparse          
-abs             graph           length          spfun           
-all             gt              logical         spones          
-amd             horzcat         lt              sprand          
-and             int16           max             sprandn         
-any             int32           min             sprandsym       
-assert          int64           minus           sprintf         
-bandwidth       int8            mldivide        sqrt            
-ceil            isa             mpower          subsasgn        
-colamd          isbanded        mrdivide        subsref         
-complex         isdiag          mtimes          sum             
-conj            isempty         ne              symamd          
-ctranspose      isequal         nnz             symrcm          
-diag            isfinite        nonzeros        times           
-digraph         isfloat         norm            transpose       
-disp            ishermitian     not             tril            
-display         isinf           numel           triu            
-dmperm          isinteger       nzmax           true            
-double          islogical       ones            uint16          
-eig             ismatrix        or              uint32          
-end             isnan           plus            uint64          
-eps             isnumeric       power           uint8           
-eq              isreal          prod            uminus          
-etree           isscalar        rdivide         uplus           
-false           issparse        real            vertcat         
-find            issymmetric     repmat          xor             
-fix             istril          reshape         zeros           
-flip            istriu          round           
-floor           isvector        sign            
-fprintf         kron            single          
-full            ldivide         size            
+GrB             disp            islogical       real            
+abs             display         ismatrix        repmat          
+acos            dmperm          isnan           reshape         
+acosh           double          isnumeric       round           
+acot            eig             isreal          sec             
+acoth           end             isscalar        sech            
+acsc            eps             issparse        sign            
+acsch           eq              issymmetric     sin             
+all             erf             istril          single          
+amd             erfc            istriu          sinh            
+and             etree           isvector        size            
+angle           exp             kron            sparse          
+any             expm1           ldivide         spfun           
+asec            false           le              spones          
+asech           find            length          sprand          
+asin            fix             log             sprandn         
+asinh           flip            log10           sprandsym       
+assert          floor           log1p           sprintf         
+atan            fprintf         log2            sqrt            
+atan2           full            logical         subsasgn        
+atanh           gamma           lt              subsindex       
+bandwidth       gammaln         max             subsref         
+bitand          ge              min             sum             
+bitcmp          graph           minus           symamd          
+bitget          gt              mldivide        symrcm          
+bitor           horzcat         mpower          tan             
+bitset          hypot           mrdivide        tanh            
+bitshift        imag            mtimes          times           
+bitxor          int16           ne              transpose       
+ceil            int32           nnz             tril            
+colamd          int64           nonzeros        triu            
+complex         int8            norm            true            
+conj            isa             not             uint16          
+cos             isbanded        numel           uint32          
+cosh            isdiag          nzmax           uint64          
+cot             isempty         ones            uint8           
+coth            isequal         or              uminus          
+csc             isfinite        plus            uplus           
+csch            isfloat         pow2            vertcat         
+ctranspose      ishermitian     power           xor             
+diag            isinf           prod            zeros           
+digraph         isinteger       rdivide         
 
 Static methods:
 
-apply           emult           issigned        reduce          
-assign          entries         kronecker       select          
-bfs             expand          ktruss          selectopinfo    
-binopinfo       extract         laplacian       semiringinfo    
-build           extracttuples   mis             speye           
-burble          eye             monoidinfo      subassign       
-chunk           finalize        mxm             threads         
-clear           format          nonz            trans           
-compact         incidence       normdiff        tricount        
-descriptorinfo  init            offdiag         type            
-dnn             isbycol         pagerank        unopinfo        
-eadd            isbyrow         prune           vreduce         
-empty           isfull          random          
-
-

Zeros are handled differently

Explicit zeros cannot be automatically dropped from a GraphBLAS matrix, like they are in MATLAB sparse matrices. In a shortest-path problem, for example, an edge A(i,j) that is missing has an infinite weight, (the monoid identity of min(x,y) is +inf). A zero edge weight A(i,j)=0 is very different from an entry that is not present in A. However, if a GraphBLAS matrix is converted into a MATLAB sparse matrix, explicit zeros are dropped, which is the convention for a MATLAB sparse matrix. They can also be dropped from a GraphBLAS matrix using the GrB.select method.

G = GrB (magic (2)) ;
+MATLAB_vs_GrB   empty           issigned        reduce          
+apply           emult           kronecker       select          
+apply2          entries         ktruss          selectopinfo    
+assign          expand          laplacian       semiringinfo    
+bfs             extract         mis             speye           
+binopinfo       extracttuples   monoidinfo      subassign       
+build           eye             mxm             threads         
+burble          finalize        nonz            trans           
+chunk           format          normdiff        tricount        
+clear           incidence       offdiag         type            
+compact         init            optype          unopinfo        
+descriptorinfo  isbycol         pagerank        vreduce         
+dnn             isbyrow         prune           
+eadd            isfull          random          
+
+

Zeros are handled differently

Explicit zeros cannot be automatically dropped from a GraphBLAS matrix, like they are in MATLAB sparse matrices. In a shortest-path problem, for example, an edge A(i,j) that is missing has an infinite weight, (the monoid identity of min(x,y) is +inf). A zero edge weight A(i,j)=0 is very different from an entry that is not present in A. However, if a GraphBLAS matrix is converted into a MATLAB sparse matrix, explicit zeros are dropped, which is the convention for a MATLAB sparse matrix. They can also be dropped from a GraphBLAS matrix using the GrB.select method.

G = GrB (magic (2)) ;
 G (1,1) = 0      % G(1,1) still appears as an explicit entry
 A = double (G)   % but it's dropped when converted to MATLAB sparse
 H = GrB.select ('nonzero', G)  % drops the explicit zeros from G
@@ -619,6 +777,7 @@
     (2,1)    4
     (1,2)    3
     (2,2)    2
+
 A =
    (2,1)        4
    (1,2)        3
@@ -632,9 +791,10 @@
     (2,1)    4
     (1,2)    3
     (2,2)    2
+
 nnz (G): 3  nnz (A): 3 nnz (H): 3
 num entries in G: 4
-

Displaying contents of a GraphBLAS matrix

Unlike MATLAB, the default is to display just a few entries of a GrB matrix. Here are all 100 entries of a 10-by-10 matrix, using a non-default disp(G,3):

G = GrB (rand (10)) ;
+

Displaying contents of a GraphBLAS matrix

Unlike MATLAB, the default is to display just a few entries of a GrB matrix. Here are all 100 entries of a 10-by-10 matrix, using a non-default disp(G,3):

G = GrB (rand (10)) ;
 % display everything:
 disp (G,3)
 
@@ -744,6 +904,7 @@
     (9,10)    0.765651
     (10,10)    0.457809
 
+
 

That was disp(G,3), so every entry was printed. It's a little long, so the default is not to print everything.

With the default display (level = 2):

G
 
 G =
@@ -782,6 +943,7 @@
     (9,3)    0.84868
     (10,3)    0.564605
     ...
+
 

That was disp(G,2) or just display(G), which is what is printed by a MATLAB statement that doesn't have a trailing semicolon. With level = 1, disp(G,1) gives just a terse summary:

disp (G,1)
 
 G =
@@ -789,7 +951,8 @@
   10x10 GraphBLAS double matrix, sparse by col:
   100 nonzeros, 100 entries
 
-

Storing a matrix by row or by column

MATLAB stores its sparse matrices by column, refered to as 'standard CSC' in SuiteSparse:GraphBLAS. In the CSC (compressed sparse column) format, each column of the matrix is stored as a list of entries, with their value and row index. In the CSR (compressed sparse row) format, each row is stored as a list of values and their column indices. GraphBLAS uses both CSC and CSR, and the two formats can be intermixed arbitrarily. In its C interface, the default format is CSR. However, for better compatibility with MATLAB, this MATLAB interface for SuiteSparse:GraphBLAS uses CSC by default instead.

rng ('default') ;
+
+

Storing a matrix by row or by column

MATLAB stores its sparse matrices by column, refered to as 'standard CSC' in SuiteSparse:GraphBLAS. In the CSC (compressed sparse column) format, each column of the matrix is stored as a list of entries, with their value and row index. In the CSR (compressed sparse row) format, each row is stored as a list of values and their column indices. GraphBLAS uses both CSC and CSR, and the two formats can be intermixed arbitrarily. In its C interface, the default format is CSR. However, for better compatibility with MATLAB, this MATLAB interface for SuiteSparse:GraphBLAS uses CSC by default instead.

rng ('default') ;
 GrB.clear ;                      % clear prior GraphBLAS settings
 fprintf ('the default format is: %s\n', GrB.format) ;
 C = sparse (rand (2))
@@ -797,10 +960,10 @@
 GrB.format (G)
 
the default format is: by col
 C =
-   (1,1)       0.8147
-   (2,1)       0.9058
-   (1,2)       0.1270
-   (2,2)       0.9134
+   (1,1)            0.814723686393179
+   (2,1)            0.905791937075619
+   (1,2)            0.126986816293506
+   (2,2)            0.913375856139019
 
 G =
 
@@ -811,6 +974,7 @@
     (2,1)    0.905792
     (1,2)    0.126987
     (2,2)    0.913376
+
 ans =
     'by col'
 

Many graph algorithms work better in CSR format, with matrices stored by row. For example, it is common to use A(i,j) for the edge (i,j), and many graph algorithms need to access the out-adjacencies of nodes, which is the row A(i,;) for node i. If the CSR format is desired, GrB.format ('by row') tells GraphBLAS to create all subsequent matrices in the CSR format. Converting from a MATLAB sparse matrix (in standard CSC format) takes a little more time (requiring a transpose), but subsequent graph algorithms can be faster.

G = GrB (C, 'by row')
@@ -828,6 +992,7 @@
     (1,2)    0.126987
     (2,1)    0.905792
     (2,2)    0.913376
+
 the format of G is:    by row
 
 H =
@@ -839,10 +1004,11 @@
     (2,1)    0.905792
     (1,2)    0.126987
     (2,2)    0.913376
+
 the format of H is:    by col
 err =
      0
-

Hypersparse matrices

SuiteSparse:GraphBLAS can use two kinds of sparse matrix data structures: standard and hypersparse, for both CSC and CSR formats. In the standard CSC format used in MATLAB, an m-by-n matrix A takes O(n+nnz(A)) space. MATLAB can create huge column vectors, but not huge matrices (when n is huge).

clear
+

Hypersparse matrices

SuiteSparse:GraphBLAS can use two kinds of sparse matrix data structures: standard and hypersparse, for both CSC and CSR formats. In the standard CSC format used in MATLAB, an m-by-n matrix A takes O(n+nnz(A)) space. MATLAB can create huge column vectors, but not huge matrices (when n is huge).

clear
 [c, huge] = computer ;
 C = sparse (huge, 1)    % MATLAB can create a huge-by-1 sparse column
 try
@@ -870,10 +1036,12 @@
   281474976710655x1 GraphBLAS double matrix, sparse by col:
   no nonzeros, no entries
 
+
 H =
 
   281474976710655x281474976710655 GraphBLAS double matrix, hypersparse by col:
   no nonzeros, no entries
+
 

Operations on huge hypersparse matrices are very fast; no component of the time or space complexity is Omega(n).

I = randperm (huge, 2) ;
 J = randperm (huge, 2) ;
 H (I,J) = magic (2) ;        % add 4 nonzeros to random locations in H
@@ -896,11 +1064,12 @@
     (78390279669562,177993304104065)    183.142
     (153933462881710,177993304104065)    143.142
     (177993304104065,177993304104065)    1403.14
-

numel uses vpa if the matrix is really huge

e1 = numel (G)               % this is huge, but still a flint
+
+

numel uses vpa if the matrix is really huge

e1 = numel (G)               % this is huge, but still a flint
 e2 = numel (H)               % this is huge^2, which needs vpa
 whos e1 e2
 
e1 =
-   2.8147e+14
+           281474976710655
 e2 =
 79228162514263774643590529025.0
   Name      Size            Bytes  Class     Attributes
@@ -915,16 +1084,16 @@
   H         281474976710655x281474976710655             1300  GrB                
   K         281474976710655x281474976710655             1300  GrB                
 
-

The mask and accumulator

When not used in overloaded operators or built-in functions, many GraphBLAS methods of the form GrB.method ( ... ) can optionally use a mask and/or an accumulator operator. If the accumulator is '+' in GrB.mxm, for example, then C = C + A*B is computed. The mask acts much like logical indexing in MATLAB. With a logical mask matrix M, C<M>=A*B allows only part of C to be assigned. If M(i,j) is true, then C(i,j) can be modified. If false, then C(i,j) is not modified.

For example, to set all values in C that are greater than 0.5 to 3:

A = rand (3)
+

The mask and accumulator

When not used in overloaded operators or built-in functions, many GraphBLAS methods of the form GrB.method ( ... ) can optionally use a mask and/or an accumulator operator. If the accumulator is '+' in GrB.mxm, for example, then C = C + A*B is computed. The mask acts much like logical indexing in MATLAB. With a logical mask matrix M, C<M>=A*B allows only part of C to be assigned. If M(i,j) is true, then C(i,j) can be modified. If false, then C(i,j) is not modified.

For example, to set all values in C that are greater than 0.5 to 3:

A = rand (3)
 C = GrB.assign (A, A > 0.5, 3) ;     % in GraphBLAS
 C1 = GrB (A) ; C1 (A > .5) = 3       % also in GraphBLAS
-C2 = A      ; C2 (A > .5) = 3       % in MATLAB
+C2 = A       ; C2 (A > .5) = 3       % in MATLAB
 err = norm (C - C1, 1)
 err = norm (C - C2, 1)
 
A =
-    0.9575    0.9706    0.8003
-    0.9649    0.9572    0.1419
-    0.1576    0.4854    0.4218
+         0.957506835434298         0.970592781760616           0.8002804688888
+         0.964888535199277         0.957166948242946         0.141886338627215
+         0.157613081677548         0.485375648722841         0.421761282626275
 
 C1 =
 
@@ -940,30 +1109,28 @@
     (1,3)    3
     (2,3)    0.141886
     (3,3)    0.421761
+
 C2 =
-    3.0000    3.0000    3.0000
-    3.0000    3.0000    0.1419
-    0.1576    0.4854    0.4218
+                         3                         3                         3
+                         3                         3         0.141886338627215
+         0.157613081677548         0.485375648722841         0.421761282626275
 err =
      0
 err =
      0
-

The descriptor

Most GraphBLAS functions of the form GrB.method ( ... ) take an optional last argument, called the descriptor. It is a MATLAB struct that can modify the computations performed by the method. 'help GrB.descriptorinfo' gives all the details. The following is a short summary of the primary settings:

d.out = 'default' or 'replace', clears C after the accum op is used.

d.mask = 'default' or 'complement', to use M or ~M as the mask matrix; 'structural', or 'structural complement', to use the pattern of M or ~M.

d.in0 = 'default' or 'transpose', to transpose A for C=A*B, C=A+B, etc.

d.in1 = 'default' or 'transpose', to transpose B for C=A*B, C=A+B, etc.

d.kind = 'default', 'GrB', 'sparse', or 'full'; the output of GrB.method.

A = sparse (rand (2)) ;
+

The descriptor

Most GraphBLAS functions of the form GrB.method ( ... ) take an optional last argument, called the descriptor. It is a MATLAB struct that can modify the computations performed by the method. 'help GrB.descriptorinfo' gives all the details. The following is a short summary of the primary settings:

d.out = 'default' or 'replace', clears C after the accum op is used.

d.mask = 'default' or 'complement', to use M or ~M as the mask matrix; 'structural', or 'structural complement', to use the pattern of M or ~M.

d.in0 = 'default' or 'transpose', to transpose A for C=A*B, C=A+B, etc.

d.in1 = 'default' or 'transpose', to transpose B for C=A*B, C=A+B, etc.

d.kind = 'default', 'GrB', 'sparse', or 'full'; the output of GrB.method.

A = sparse (rand (2)) ;
 B = sparse (rand (2)) ;
 C1 = A'*B ;
 C2 = GrB.mxm ('+.*', A, B, struct ('in0', 'transpose')) ;
 err = norm (C1-C2,1)
 
err =
      0
-

Integer arithmetic is different in GraphBLAS

MATLAB supports integer arithmetic on its full matrices, using int8, int16, int32, int64, uint8, uint16, uint32, or uint64 data types. None of these integer data types can be used to construct a MATLAB sparse matrix, which can only be double, double complex, or logical. Furthermore, C=A*B is not defined for integer types in MATLAB, except when A and/or B are scalars.

GraphBLAS supports all of those types for its sparse matrices (except for complex, which will be added in the future). All operations are supported, including C=A*B when A or B are any integer type, for all 1,865 semirings (1,040 of which are unique).

However, integer arithmetic differs in GraphBLAS and MATLAB. In MATLAB, integer values saturate if they exceed their maximum value. In GraphBLAS, integer operators act in a modular fashion. The latter is essential when computing C=A*B over a semiring. A saturating integer operator cannot be used as a monoid since it is not associative.

The C API for GraphBLAS allows for the creation of arbitrary user-defined types, so it would be possible to create different binary operators to allow element-wise integer operations to saturate, perhaps:

C = GrB.eadd('+saturate',A,B)
-

This would require an extension to this MATLAB interface.

C = uint8 (magic (3)) ;
+

Integer arithmetic is different in GraphBLAS

MATLAB supports integer arithmetic on its full matrices, using int8, int16, int32, int64, uint8, uint16, uint32, or uint64 data types. None of these integer data types can be used to construct a MATLAB sparse matrix, which can only be double, double complex, or logical. Furthermore, C=A*B is not defined for integer types in MATLAB, except when A and/or B are scalars.

GraphBLAS supports all of those types for its sparse matrices. All operations are supported, including C=A*B when A or B are any integer type, in 1000s of semirings.

However, integer arithmetic differs in GraphBLAS and MATLAB. In MATLAB, integer values saturate if they exceed their maximum value. In GraphBLAS, integer operators act in a modular fashion. The latter is essential when computing C=A*B over a semiring. A saturating integer operator cannot be used as a monoid since it is not associative.

C = uint8 (magic (3)) ;
 G = GrB (C) ;
 C1 = C * 40
-C2 = G * 40
-C3 = double (G) * 40 ;
+C2 = G * uint8 (40)
 S = double (C1 < 255) ;
 assert (isequal (double (C1).*S, double (C2).*S))
-assert (isequal (nonzeros (C2), double (mod (nonzeros (C3), 256))))
 
C1 =
   3×3 uint8 matrix
    255    40   240
@@ -984,7 +1151,8 @@
     (1,3)   240
     (2,3)   24
     (3,3)   80
-

An example graph algorithm: breadth-first search

The breadth-first search of a graph finds all nodes reachable from the source node, and their level, v. v=GrB.bfs(A,s) or v=bfs_matlab(A,s) compute the same thing, but GrB.bfs uses GraphBLAS matrices and operations, while bfs_matlab uses pure MATLAB operations. v is defined as v(s) = 1 for the source node, v(i) = 2 for nodes adjacent to the source, and so on.

clear
+
+

An example graph algorithm: breadth-first search

The breadth-first search of a graph finds all nodes reachable from the source node, and their level, v. v=GrB.bfs(A,s) or v=bfs_matlab(A,s) compute the same thing, but GrB.bfs uses GraphBLAS matrices and operations, while bfs_matlab uses pure MATLAB operations. v is defined as v(s) = 1 for the source node, v(i) = 2 for nodes adjacent to the source, and so on.

clear
 rng ('default') ;
 n = 1e5 ;
 A = logical (sprandn (n, n, 1e-3)) ;
@@ -1005,10 +1173,10 @@
     matlab_time / gb_time) ;
 
 nodes reached: 100000 of 100000
-GraphBLAS time: 0.304218 sec
-MATLAB time:    0.659991 sec
-Speedup of GraphBLAS over MATLAB: 2.16947
-

Example graph algorithm: Luby's method in GraphBLAS

The GrB.mis.m function is variant of Luby's randomized algorithm [Luby 1985]. It is a parallel method for finding an maximal independent set of nodes, where no two nodes are adjacent. See the GraphBLAS/@GrB/GrB.mis.m function for details. The graph must be symmetric with a zero-free diagonal, so A is symmetrized first and any diagonal entries are removed.

A = GrB (A) ;
+GraphBLAS time: 0.33517 sec
+MATLAB time:    0.799412 sec
+Speedup of GraphBLAS over MATLAB: 2.3851
+

Example graph algorithm: Luby's method in GraphBLAS

The GrB.mis function is variant of Luby's randomized algorithm [Luby 1985]. It is a parallel method for finding an maximal independent set of nodes, where no two nodes are adjacent. See the GraphBLAS/@GrB/mis.m function for details. The graph must be symmetric with a zero-free diagonal, so A is symmetrized first and any diagonal entries are removed.

A = GrB (A) ;
 A = GrB.offdiag (A|A') ;
 
 tic
@@ -1029,11 +1197,11 @@
 S = A (notp, p) ;
 deg = GrB.vreduce ('+.int64', S) ;
 assert (logical (all (deg > 0)))
-
Elapsed time is 0.500012 seconds.
+
Elapsed time is 0.542797 seconds.
 # nodes in the graph: 100000
 # edges: : 9.9899e+06
 size of maximal independent set found: 2811
-

Sparse deep neural network

The 2019 MIT GraphChallenge (see http://graphchallenge.org) is to solve a set of large sparse deep neural network problems. In this demo, the MATLAB reference solution is compared with a solution using GraphBLAS, for a randomly constructed neural network. See the GrB.dnn and dnn_matlab.m functions for details.

clear
+

Sparse deep neural network

The 2019 MIT GraphChallenge (see http://graphchallenge.org) is to solve a set of large sparse deep neural network problems. In this demo, the MATLAB reference solution is compared with a solution using GraphBLAS, for a randomly constructed neural network. See the GrB.dnn and dnn_matlab.m functions for details.

clear
 rng ('default') ;
 nlayers = 16 ;
 nneurons = 4096 ;
@@ -1059,14 +1227,14 @@
 
# layers:   16
 # neurons:  4096
 # features: 30000
-construct problem time: 5.39236 sec
-setup time: 0.269235 sec
-

Solving the sparse deep neural network problem with GraphbLAS

Please wait ...

tic
+construct problem time: 6.02037 sec
+setup time: 0.284302 sec
+

Solving the sparse deep neural network problem with GraphbLAS

Please wait ...

tic
 Y1 = GrB.dnn (W_gb, bias_gb, Y0_gb) ;
 gb_time = toc ;
 fprintf ('total time in GraphBLAS: %g sec\n', gb_time) ;
-
total time in GraphBLAS: 11.6755 sec
-

Solving the sparse deep neural network problem with MATLAB

Please wait ...

tic
+
total time in GraphBLAS: 12.7092 sec
+

Solving the sparse deep neural network problem with MATLAB

Please wait ...

tic
 Y2 = dnn_matlab (W, bias, Y0) ;
 matlab_time = toc ;
 fprintf ('total time in MATLAB:    %g sec\n', matlab_time) ;
@@ -1074,11 +1242,11 @@
     matlab_time / gb_time) ;
 
 err = norm (Y1-Y2,1)
-
total time in MATLAB:    103.288 sec
-Speedup of GraphBLAS over MATLAB: 8.8465
+
total time in MATLAB:    105.194 sec
+Speedup of GraphBLAS over MATLAB: 8.27702
 err =
      0
-

For objects, GraphBLAS has better colon notation than MATLAB

The MATLAB notation C = A (start:inc:fini) is very handy, and it works great if A is a MATLAB matrix. But for objects like the GraphBLAS matrix, MATLAB starts by creating the explicit index vector I = start:inc:fini. That's fine if the matrix is modest in size, but GraphBLAS can construct huge matrices. The problem is that 1:n cannot be explicitly constructed when n is huge.

The C API for GraphBLAS can represent the colon notation start:inc:fini in an implicit manner, so it can do the indexing without actually forming the explicit list I = start:inc:fini. But there is no access to this method using the MATLAB notation start:inc:fini.

Thus, to compute C = A (start:inc:fini) for very huge matrices, you need to use use a cell array to represent the colon notation, as { start, inc, fini }, instead of start:inc:fini. See 'help GrB.extract' and 'help.gbsubassign' for, for C(I,J)=A. The syntax isn't conventional, but it is far faster than the MATLAB colon notation for objects, and takes far less memory when I is huge.

n = 1e14 ;
+

For objects, GraphBLAS has better colon notation than MATLAB

The MATLAB notation C = A (start:inc:fini) is very handy, and it works great if A is a MATLAB matrix. But for objects like the GraphBLAS matrix, MATLAB starts by creating the explicit index vector I = start:inc:fini. That's fine if the matrix is modest in size, but GraphBLAS can construct huge matrices. The problem is that 1:n cannot be explicitly constructed when n is huge.

The C API for GraphBLAS can represent the colon notation start:inc:fini in an implicit manner, so it can do the indexing without actually forming the explicit list I = start:inc:fini. But there is no access to this method using the MATLAB notation start:inc:fini.

Thus, to compute C = A (start:inc:fini) for very huge matrices, you need to use use a cell array to represent the colon notation, as { start, inc, fini }, instead of start:inc:fini. See 'help GrB.extract', 'help GrB.assign' for the functional form. For the overloaded syntax C(I,J)=A and C=A(I,J), see 'help GrB/subsasgn' and 'help GrB/subsfref'. The cell array syntax isn't conventional, but it is far faster than the MATLAB colon notation for objects, and takes far less memory when I is huge.

n = 1e14 ;
 H = GrB (n, n) ;            % a huge empty matrix
 I = [1 1e9 1e12 1e14] ;
 M = magic (4)
@@ -1108,6 +1276,7 @@
     (1,1000000000000)    3
     (1000000000,1000000000000)    10
     (1000000000000,1000000000000)    6
+
 
try
     % try to compute the same thing with colon
     % notation (1:1e13), but this fails:
@@ -1123,7 +1292,7 @@
          cause: {}
          stack: [4×1 struct]
     Correction: []
-

Iterative solvers work as-is

Many built-in functions work with GraphBLAS matrices unmodified.

A = sparse (rand (4)) ;
+

Iterative solvers work as-is

Many built-in functions work with GraphBLAS matrices unmodified.

A = sparse (rand (4)) ;
 b = sparse (rand (4,1)) ;
 x = gmres (A,b)
 norm (A*x-b)
@@ -1131,40 +1300,40 @@
 norm (A*x-b)
 
gmres converged at iteration 4 to a solution with relative residual 0.
 x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
+          0.91047557490445
+          3.89492850585206
+        -0.569511178041979
+         -1.38669683854936
 ans =
-   8.6711e-16
+      8.67111901826273e-16
 gmres converged at iteration 4 to a solution with relative residual 0.
 x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
+         0.910475574904404
+           3.8949285058519
+         -0.56951117804191
+          -1.3866968385493
 ans =
-   7.2802e-16
-

... even in single precision

x = gmres (GrB(A,'single'), GrB(b,'single'))
+      7.28021923224409e-16
+

... even in single precision

x = gmres (GrB(A,'single'), GrB(b,'single'))
 norm (A*x-b)
 
gmres converged at iteration 4 to a solution with relative residual 0.
 x =
-    0.9105
-    3.8949
-   -0.5695
-   -1.3867
+         0.910472507135207
+          3.89491683958708
+        -0.569506481916661
+          -1.3866920717142
 ans =
-   3.5566e-07
+       8.3369210904823e-08
 

Both of the following uses of minres (A,b) fail to converge because A is not symmetric, as the method requires. Both failures are correctly reported, and both the MATLAB version and the GraphBLAS version return the same incorrect vector x.

x = minres (A, b)
 x = minres (GrB(A), GrB(b))
 
minres stopped at iteration 4 without converging to the desired tolerance 1e-06
 because the maximum number of iterations was reached.
 The iterate returned (number 4) has relative residual 0.21.
 x =
-    0.2489
-    0.2081
-    0.0700
-    0.3928
+         0.248941606720887
+         0.208128063873183
+        0.0699707140888991
+         0.392812027589062
 minres stopped at iteration 4 without converging to the desired tolerance 1e-06
 because the maximum number of iterations was reached.
 The iterate returned (number 4) has relative residual 0.21.
@@ -1178,6 +1347,7 @@
     (2,1)    0.208128
     (3,1)    0.0699707
     (4,1)    0.392812
+
 

With a proper symmetric matrix

A = A+A' ;
 x = minres (A, b)
 norm (A*x-b)
@@ -1185,12 +1355,12 @@
 norm (A*x-b)
 
minres converged at iteration 4 to a solution with relative residual 1.3e-11.
 x =
- -114.0616
-   -1.4211
-  134.8227
-    2.0694
+         -114.061616682974
+         -1.42110186668133
+          134.822699973567
+          2.06940490708633
 ans =
-   1.3650e-11
+      1.36498610101886e-11
 minres converged at iteration 4 to a solution with relative residual 1.3e-11.
 
 x =
@@ -1202,9 +1372,10 @@
     (2,1)    -1.4211
     (3,1)    134.823
     (4,1)    2.0694
+
 ans =
-   1.3650e-11
-

Extreme performance differences between GraphBLAS and MATLAB.

The GraphBLAS operations used so far are perhaps 2x to 50x faster than the corresponding MATLAB operations, depending on how many cores your computer has. To run a demo illustrating a 500x or more speedup versus MATLAB, run this demo:

  gbdemo2

It will illustrate an assignment C(I,J)=A that can take under a second in GraphBLAS but several minutes in MATLAB. To make the comparsion even more dramatic, try:

  gbdemo2 (20000)

assuming you have enough memory. The gbdemo2 is not part of this demo since it can take a long time; it tries a range of problem sizes, and each one takes several minutes in MATLAB.

Sparse logical indexing is much, much faster in GraphBLAS

The mask in GraphBLAS acts much like logical indexing in MATLAB, but it is not quite the same. MATLAB logical indexing takes the form:

     C (M) = A (M)

which computes the same thing as the GraphBLAS statement:

     C = GrB.assign (C, M, A)

The GrB.assign statement computes C(M)=A(M), and it is vastly faster than C(M)=A(M), even if the time to convert the GrB matrix back to a MATLAB sparse matrix is included.

GraphBLAS can also compute C (M) = A (M) using overloaded operators for subsref and subsasgn, but C = GrB.assign (C, M, A) is a bit faster.

First, both methods in GraphBLAS (both are very fast):

clear
+      1.36498610101886e-11
+

Extreme performance differences between GraphBLAS and MATLAB.

The GraphBLAS operations used so far are perhaps 2x to 50x faster than the corresponding MATLAB operations, depending on how many cores your computer has. To run a demo illustrating a 500x or more speedup versus MATLAB, run this demo:

  gbdemo2

It will illustrate an assignment C(I,J)=A that can take under a second in GraphBLAS but several minutes in MATLAB. To make the comparsion even more dramatic, try:

  gbdemo2 (20000)

assuming you have enough memory.

Sparse logical indexing is much, much faster in GraphBLAS

The mask in GraphBLAS acts much like logical indexing in MATLAB, but it is not quite the same. MATLAB logical indexing takes the form:

     C (M) = A (M)

which computes the same thing as the GraphBLAS statement:

     C = GrB.assign (C, M, A)

The GrB.assign statement computes C(M)=A(M), and it is vastly faster than C(M)=A(M), even if the time to convert the GrB matrix back to a MATLAB sparse matrix is included.

GraphBLAS can also compute C (M) = A (M) using overloaded operators for subsref and subsasgn, but C = GrB.assign (C, M, A) is a bit faster.

Here are both methods in GraphBLAS (both are very fast). Setting up:

clear
 n = 4000 ;
 tic
 C = sprand (n, n, 0.1) ;
@@ -1214,32 +1385,26 @@
 fprintf ('nnz(C): %g, nnz(M): %g, nnz(A): %g\n', ...
     nnz(C), nnz(M), nnz(A)) ;
 fprintf ('\nsetup time:     %g sec\n', t_setup) ;
+
nnz(C): 1.5226e+06, nnz(M): 761163, nnz(A): 1.52245e+06
 
-% include the time to convert C1 from a GraphBLAS
-% matrix to a MATLAB sparse matrix:
-tic
+setup time:     1.08586 sec
+

First method in GraphBLAS, with GrB.assign

Including the time to convert C1 from a GraphBLAS matrix to a MATLAB sparse matrix:

tic
 C1 = GrB.assign (C, M, A) ;
 C1 = double (C1) ;
 gb_time = toc ;
 fprintf ('\nGraphBLAS time: %g sec for GrB.assign\n', gb_time) ;
-
-% now using overloaded operators, also include the time to
-% convert back to a MATLAB sparse matrix, for good measure:
-A2 = GrB (A) ;
+
+GraphBLAS time: 0.0875537 sec for GrB.assign
+

Second method in GraphBLAS, with C(M)=A(M)

now using overloaded operators, also include the time to convert back to a MATLAB sparse matrix, for good measure:

A2 = GrB (A) ;
 C2 = GrB (C) ;
 tic
 C2 (M) = A2 (M) ;
 C2 = double (C2) ;
 gb_time2 = toc ;
 fprintf ('\nGraphBLAS time: %g sec for C(M)=A(M)\n', gb_time2) ;
-
nnz(C): 1.5226e+06, nnz(M): 761163, nnz(A): 1.52245e+06
-
-setup time:     1.06526 sec
-
-GraphBLAS time: 0.0899941 sec for GrB.assign
-
-GraphBLAS time: 0.185244 sec for C(M)=A(M)
-

Please wait, this will take about 10 minutes or so ...

tic
+
+GraphBLAS time: 0.181763 sec for C(M)=A(M)
+

Now with MATLAB matrices, with C(M)=A(M)

Please wait, this will take about 10 minutes or so ...

tic
 C (M) = A (M) ;
 matlab_time = toc ;
 
@@ -1255,16 +1420,16 @@
 C1 - C
 C2 - C
 
-GraphBLAS time: 0.0899941 sec (GrB.assign)
+GraphBLAS time: 0.0875537 sec (GrB.assign)
 
-GraphBLAS time: 0.185244 sec (overloading)
-MATLAB time:    625.603 sec
-Speedup of GraphBLAS over MATLAB: 3377.19
+GraphBLAS time: 0.181763 sec (overloading)
+MATLAB time:    628.349 sec
+Speedup of GraphBLAS over MATLAB: 3456.96
 ans =
    All zero sparse: 4000×4000
 ans =
    All zero sparse: 4000×4000
-

Limitations and their future solutions

The MATLAB interface for SuiteSparse:GraphBLAS is a work-in-progress. It has some limitations, most of which will be resolved over time.

(1) Nonblocking mode:

GraphBLAS has a 'non-blocking' mode, in which operations can be left pending and completed later. SuiteSparse:GraphBLAS uses the non-blocking mode to speed up a sequence of assignment operations, such as C(I,J)=A. However, in its MATLAB interface, this would require a MATLAB mexFunction to modify its inputs. That breaks the MATLAB API standard, so it cannot be safely done. As a result, using GraphBLAS via its MATLAB interface can be slower than when using its C API. This restriction would not be a limitation if GraphBLAS were to be incorporated into MATLAB itself, but there is likely no way to do this in a mexFunction interface to GraphBLAS.

(2) Complex matrices:

GraphBLAS can operate on matrices with arbitrary user-defined types and operators. The only constraint is that the type be a fixed sized typedef that can be copied with the ANSI C memcpy; variable-sized types are not yet supported. However, in this MATLAB interface, SuiteSparse:GraphBLAS has access to only predefined types, operators, and semirings. Complex types and operators will be added to this MATLAB interface in the future. They already appear in the C version of GraphBLAS, with user-defined operators in GraphBLAS/Demo/Source/usercomplex.c.

(3) Integer element-wise operations:

Integer operations in MATLAB saturate, so that uint8(255)+1 is 255. To allow for integer monoids, GraphBLAS uses modular arithmetic instead. This is the only way that C=A*B can be defined for integer semirings. However, saturating integer operators could be added in the future, so that element- wise integer operations on GraphBLAS sparse integer matrices could work just the same as their MATLAB counterparts.

So in the future, you could perhaps write this, for both sparse and dense integer matrices A and B:

     C = GrB.eadd ('+saturate.int8', A, B)

to compute the same thing as C=A+B in MATLAB for its full int8 matrices. Note that MATLAB can do this only for dense integer matrices, since it doesn't support sparse integer matrices.

(4) Faster methods:

Most methods in this MATLAB interface are based on efficient parallel C functions in GraphBLAS itself, and are typically as fast or faster than the equivalent built-in operators and functions in MATLAB.

There are few notable exceptions; these will be addressed in the future. Dense matrices and vectors held as GraphBLAS objects are slower than their MATLAB counterparts. horzcat and vertcat, for [A B] and [A;B] when either A or B are GraphBLAS matrices, are also slow, as illustrated below in the next example.

Other methods that will be faster in the future include bandwidth, istriu, istril, eps, ceil, floor, round, fix, isfinite, isinf, isnan, spfun, and A.^B. These methods are currently implemented in m-files, not in efficient parallel C functions.

Here is an example that illustrates the performance of C = [A B]

clear
+

Limitations and their future solutions

The MATLAB interface for SuiteSparse:GraphBLAS is a work-in-progress. It has some limitations, most of which will be resolved over time.

(1) Nonblocking mode:

GraphBLAS has a 'non-blocking' mode, in which operations can be left pending and completed later. SuiteSparse:GraphBLAS uses the non-blocking mode to speed up a sequence of assignment operations, such as C(I,J)=A. However, in its MATLAB interface, this would require a MATLAB mexFunction to modify its inputs. That breaks the MATLAB API standard, so it cannot be safely done. As a result, using GraphBLAS via its MATLAB interface can be slower than when using its C API.

(2) Integer element-wise operations:

Integer operations in MATLAB saturate, so that uint8(255)+1 is 255. To allow for integer monoids, GraphBLAS uses modular arithmetic instead. This is the only way that C=A*B can be defined for integer semirings. However, saturating integer operators could be added in the future, so that element- wise integer operations on GraphBLAS sparse integer matrices could work just the same as their MATLAB counterparts.

So in the future, you could perhaps write this, for both sparse and dense integer matrices A and B:

     C = GrB.eadd ('+saturate.int8', A, B)

to compute the same thing as C=A+B in MATLAB for its full int8 matrices. Note that MATLAB can do this only for dense integer matrices, since it doesn't support sparse integer matrices.

(3) Faster methods:

Most methods in this MATLAB interface are based on efficient parallel C functions in GraphBLAS itself, and are typically as fast or faster than the equivalent built-in operators and functions in MATLAB.

There are few notable exceptions; these will be addressed in the future. Dense matrices and vectors held as GraphBLAS objects are slower than their MATLAB counterparts. horzcat and vertcat, for [A B] and [A;B] when either A or B are GraphBLAS matrices, are also slow, as illustrated below in the next example.

Other methods that will be faster in the future include bandwidth, istriu, istril, isdiag, reshape, issymmetric, and ishermitian.

Here is an example that illustrates the performance of C = [A B]

clear
 A = sparse (rand (2000)) ;
 B = sparse (rand (2000)) ;
 tic
@@ -1287,9 +1452,9 @@
 
err =
      0
 
-MATLAB: 0.0669017 sec, GraphBLAS: 0.345537 sec
-GraphBLAS is slower by a factor of 5.16484
-

(5) Linear indexing:

If A is an m-by-n 2D MATLAB matrix, with n > 1, A(:) is a column vector of length m*n. The index operation A(i) accesses the ith entry in the vector A(:). This is called linear indexing in MATLAB. It is not yet available for GraphBLAS matrices in this MATLAB interface to GraphBLAS, but it could be added in the future.

(6) Implicit singleton dimension expansion

In MATLAB C=A+B where A is m-by-n and B is a 1-by-n row vector implicitly expands B to a matrix, computing C(i,j)=A(i,j)+B(j). This implicit expansion is not yet suported in GraphBLAS with C=A+B. However, it can be done with C = GrB.mxm ('+.+', A, diag(GrB(B))). That's an nice example of the power of semirings, but it's not immediately obvious, and not as clear a syntax as C=A+B. The GraphBLAS/@GrB/dnn.m function uses this 'plus.plus' semiring to apply the bias to each neuron.

A = magic (3)
+MATLAB: 0.0693146 sec, GraphBLAS: 0.389899 sec
+GraphBLAS is slower by a factor of 5.62506
+

(4) Linear indexing:

If A is an m-by-n 2D MATLAB matrix, with n > 1, A(:) is a column vector of length m*n. The index operation A(i) accesses the ith entry in the vector A(:). This is called linear indexing in MATLAB. It is not yet available for GraphBLAS matrices in this MATLAB interface to GraphBLAS, but will be added in the future.

(5) Implicit singleton dimension expansion

In MATLAB C=A+B where A is m-by-n and B is a 1-by-n row vector implicitly expands B to a matrix, computing C(i,j)=A(i,j)+B(j). This implicit expansion is not yet suported in GraphBLAS with C=A+B. However, it can be done with C = GrB.mxm ('+.+', A, diag(GrB(B))). That's a nice example of the power of semirings, but it's not immediately obvious, and not as clear a syntax as C=A+B. The GraphBLAS/@GrB/dnn.m function uses this 'plus.plus' semiring to apply the bias to each neuron.

A = magic (3)
 B = 1000:1000:3000
 C1 = A + B
 C2 = GrB.mxm ('+.+', A, diag (GrB (B)))
@@ -1319,211 +1484,25 @@
     (1,3)    3006
     (2,3)    3007
     (3,3)    3002
+
 err =
      0
-

GraphBLAS operations

In addition to the overloaded operators (such as C=A*B) and overloaded functions (such as L=tril(A)), GraphBLAS also has methods of the form GrB.method, listed on the next page. Most of them take an optional input matrix Cin, which is the initial value of the matrix C for the expression below, an optional mask matrix M, and an optional accumulator operator.

    C<#M,replace> = accum (C, T)

In the above expression, #M is either empty (no mask), M (with a mask matrix) or ~M (with a complemented mask matrix), as determined by the descriptor. 'replace' can be used to clear C after it is used in accum(C,T) but before it is assigned with C<...> = Z, where Z=accum(C,T). The matrix T is the result of some operation, such as T=A*B for GrB.mxm, or T=op(A,B) for GrB.eadd.

A summary of these GrB.methods is on the next pages.

Methods for the GrB class:

These methods operate on GraphBLAS matrices only, and they overload
-the existing MATLAB functions of the same name.
-
C = GrB (...)           construct a GraphBLAS matrix
-C = sparse (G)          makes a copy of a GrB matrix
-C = full (G, ...)       adds explicit zeros or id values to a GrB matrix
-C = double (G)          cast GrB matrix to MATLAB sparse double matrix
-C = logical (G)         cast GrB matrix to MATLAB sparse logical matrix
-C = complex (G)         cast GrB matrix to MATLAB sparse complex
-C = single (G)          cast GrB matrix to MATLAB full single matrix
-C = int8 (G)            cast GrB matrix to MATLAB full int8 matrix
-C = int16 (G)           cast GrB matrix to MATLAB full int16 matrix
-C = int32 (G)           cast GrB matrix to MATLAB full int32 matrix
-C = int64 (G)           cast GrB matrix to MATLAB full int64 matrix
-C = uint8 (G)           cast GrB matrix to MATLAB full uint8 matrix
-C = uint16 (G)          cast GrB matrix to MATLAB full uint16 matrix
-C = uint32 (G)          cast GrB matrix to MATLAB full uint32 matrix
-C = uint64 (G)          cast GrB matrix to MATLAB full uint64 matrix
-C = cast (G,...)        cast GrB matrix to MATLAB matrix (as above)
-
X = nonzeros (G)        extract all entries from a GrB matrix
-[I,J,X] = find (G)      extract all entries from a GrB matrix
-C = spones (G)          return pattern of GrB matrix
-disp (G, level)         display a GrB matrix G
-display (G)             display a GrB matrix G; same as disp(G,2)
-mn = numel (G)          m*n for an m-by-n GrB matrix G
-e = nnz (G)             number of entries in a GrB matrix G
-e = nzmax (G)           number of entries in a GrB matrix G
-[m n] = size (G)        size of a GrB matrix G
-n = length (G)          length of a GrB vector
-s = isempty (G)         true if any dimension of G is zero
-s = issparse (G)        true for any GrB matrix G
-s = ismatrix (G)        true for any GrB matrix G
-s = isvector (G)        true if m=1 or n=1, for an m-by-n GrB matrix G
-s = iscolumn (G)        true if n=1, for an m-by-n GrB matrix G
-s = isrow (G)           true if m=1, for an m-by-n GrB matrix G
-s = isscalar (G)        true if G is a 1-by-1 GrB matrix
-s = isnumeric (G)       true for any GrB matrix G (even logical)
-s = isfloat (G)         true if GrB matrix is double, single, complex
-s = isreal (G)          true if GrB matrix is not complex
-s = isinteger (G)       true if GrB matrix is int8, int16, ..., uint64
-s = islogical (G)       true if GrB matrix is logical
-s = isa (G, classname)  check if a GrB matrix is of a specific class
-
C = diag (G,k)          diagonal matrices and diagonals of GrB matrix G
-L = tril (G,k)          lower triangular part of GrB matrix G
-U = triu (G,k)          upper triangular part of GrB matrix G
-C = kron (A,B)          Kronecker product
-C = repmat (G, ...)     replicate and tile a GraphBLAS matrix
-C = reshape (G, ...)    reshape a GraphBLAS matrix
-C = abs (G)             absolute value
-C = sign (G)            signum function
-s = istril (G)          true if G is lower triangular
-s = istriu (G)          true if G is upper triangular
-s = isbanded (G,...)    true if G is banded
-s = isdiag (G)          true if G is diagonal
-s = ishermitian (G)     true if G is Hermitian
-s = issymmetric (G)     true if G is symmetric
-[lo,hi] = bandwidth (G) determine the lower & upper bandwidth of G
-C = sum (G, option)     reduce via sum, to vector or scalar
-C = prod (G, option)    reduce via product, to vector or scalar
-s = norm (G, kind)      1-norm or inf-norm of a GrB matrix
-C = max (G, ...)        reduce via max, to vector or scalar
-C = min (G, ...)        reduce via min, to vector or scalar
-C = any (G, ...)        reduce via '|', to vector or scalar
-C = all (G, ...)        reduce via '&', to vector or scalar
-
C = sqrt (G)            element-wise square root
-C = eps (G)             floating-point spacing
-C = ceil (G)            round towards infinity
-C = floor (G)           round towards -infinity
-C = round (G)           round towards nearest
-C = fix (G)             round towards zero
-C = isfinite (G)        test if finite
-C = isinf (G)           test if infinite
-C = isnan (G)           test if NaN
-C = spfun (fun, G)      evaluate a function on the entries of G
-p = amd (G)             approximate minimum degree ordering
-p = colamd (G)          column approximate minimum degree ordering
-p = symamd (G)          approximate minimum degree ordering
-p = symrcm (G)          reverse Cuthill-McKee ordering
-[...] = dmperm (G)      Dulmage-Mendelsohn permutation
-parent = etree (G)      elimination tree
-C = conj (G)            complex conjugate
-C = real (G)            real part of a complex GraphBLAS matrix
-[V, ...] = eig (G,...)  eigenvalues and eigenvectors
-assert (G)              generate an error if G is false
-C = zeros (...,'like',G)   all-zero matrix, same type as G
-C = false (...,'like',G)   all-false logical matrix
-C = ones (...,'like',G)    matrix with all ones, same type as G
-

Operator overloading:

C = plus (A, B)         C = A + B
-C = minus (A, B)        C = A - B
-C = uminus (G)          C = -G
-C = uplus (G)           C = +G
-C = times (A, B)        C = A .* B
-C = mtimes (A, B)       C = A * B
-C = rdivide (A, B)      C = A ./ B
-C = ldivide (A, B)      C = A .\ B
-C = mrdivide (A, B)     C = A / B
-C = mldivide (A, B)     C = A \ B
-C = power (A, B)        C = A .^ B
-C = mpower (A, B)       C = A ^ B
-C = lt (A, B)           C = A < B
-C = gt (A, B)           C = A > B
-C = le (A, B)           C = A <= B
-C = ge (A, B)           C = A >= B
-C = ne (A, B)           C = A ~= B
-C = eq (A, B)           C = A == B
-C = and (A, B)          C = A & B
-C = or (A, B)           C = A | B
-C = not (G)             C = ~G
-C = ctranspose (G)      C = G'
-C = transpose (G)       C = G.'
-C = horzcat (A, B)      C = [A , B]
-C = vertcat (A, B)      C = [A ; B]
-C = subsref (A, I, J)   C = A (I,J) or C = A (M)
-C = subsasgn (A, I, J)  C (I,J) = A
-index = end (A, k, n)   for object indexing, A(1:end,1:end)
-

Static Methods:

The Static Methods for the GrB class can be used on input matrices of
-any kind: GraphBLAS sparse matrices, MATLAB sparse matrices, or
-MATLAB dense matrices, in any combination.  The output matrix Cout is
-a GraphBLAS matrix, by default, but can be optionally returned as a
-MATLAB sparse or dense matrix.  The static methods divide into two
-categories: those that perform basic functions, and the GraphBLAS
-operations that use the mask/accum.
-

GraphBLAS basic functions:

GrB.clear                    clear GraphBLAS workspace and settings
-GrB.descriptorinfo (d)       list properties of a descriptor
-GrB.unopinfo (op, type)      list properties of a unary operator
-GrB.binopinfo (op, type)     list properties of a binary operator
-GrB.monoidinfo (op, type)    list properties of a monoid
-GrB.semiringinfo (s, type)   list properties of a semiring
-t = GrB.threads (t)          set/get # of threads to use in GraphBLAS
-c = GrB.chunk (c)            set/get chunk size to use in GraphBLAS
-b = GrB.burble (b)           set/get burble (diagnostic output)
-result = GrB.entries (G,...) count or query entries in a matrix
-result = GrB.nonz (G,...)    count or query nonzeros in a matrix
-C = GrB.prune (A, id)        prune entries equal to id
-C = GrB.offdiag (A)          prune diagonal entries
-s = GrB.isfull (A)           true if all entries present
-[C,I,J] = GrB.compact (A,id) remove empty rows and columns
-G = GrB.empty (m, n)         return an empty GraphBLAS matrix
-s = GrB.type (A)             get the type of a MATLAB or GrB matrix A
-s = GrB.issigned (type)      true if type is signed
-f = GrB.format (f)           set/get matrix format to use in GraphBLAS
-s = GrB.isbyrow (A)          true if format f A is 'by row'
-s = GrB.isbycol (A)          true if format f A is 'by col'
-C = GrB.expand (scalar, A)   expand a scalar (C = scalar*spones(A))
-C = GrB.eye                  identity matrix of any type
-C = GrB.speye                identity matrix (of type 'double')
-C = GrB.build (I, J, X, m, n, dup, type, desc)
-                             build a GrB matrix from list of entries
-[I,J,X] = GrB.extracttuples (A, desc)
-                             extract all entries from a matrix
-s = GrB.normdiff (A, B, kind)   norm (A-B,kind)
-

GraphBLAS operations with Cout, mask M, and accum.

Cout = GrB.mxm (Cin, M, accum, semiring, A, B, desc)
-                sparse matrix-matrix multiplication over a semiring
-Cout = GrB.select (Cin, M, accum, op, A, b, desc)
-                select a subset of entries from a matrix
-Cout = GrB.assign (Cin, M, accum, A, I, J, desc)
-                sparse matrix assignment, such as C(I,J)=A
-Cout = GrB.subassign (Cin, M, accum, A, I, J, desc)
-                sparse matrix assignment, such as C(I,J)=A
-Cout = GrB.vreduce (Cin, M, accum, op, A, desc)
-                reduce a matrix to a vector
-Cout = GrB.reduce (Cin, accum, op, A, desc)
-                reduce a matrix to a scalar
-Cout = GrB.kronecker (Cin, M, accum, op, A, B, desc)
-                Kronecker product
-Cout = GrB.trans (Cin, M, accum, A, desc)
-                transpose a matrix
-Cout = GrB.eadd (Cin, M, accum, op, A, B, desc)
-                element-wise addition
-Cout = GrB.emult (Cin, M, accum, op, A, B, desc)
-                element-wise multiplication
-Cout = GrB.apply (Cin, M, accum, op, A, desc)
-                apply a unary operator
-Cout = GrB.extract (Cin, M, accum, A, I, J, desc)
-                extract submatrix, like C=A(I,J) in MATLAB
-

GraphBLAS operations (with Cout, Cin arguments) take the following form:

C<#M,replace> = accum (C, operation (A or A', B or B'))
-
C is both an input and output matrix.  In this MATLAB interface to
-GraphBLAS, it is split into Cin (the value of C on input) and Cout
-(the value of C on output).  M is the optional mask matrix, and #M is
-either M or !M depending on whether or not the mask is complemented
-via the desc.mask option.  The replace option is determined by
-desc.out; if present, C is cleared after it is used in the accum
-operation but before the final assignment.  A and/or B may optionally
-be transposed via the descriptor fields desc.in0 and desc.in1,
-respectively.  To select the format of Cout, use desc.format.  See
-GrB.descriptorinfo for more details.
-
accum is optional; if not is not present, then the operation becomes
-C<...> = operation(A,B).  Otherwise, C = C + operation(A,B) is
-computed where '+' is the accum operator.  It acts like a sparse
-matrix addition (see GrB.eadd), in terms of the structure of the
-result C, but any binary operator can be used.
-
The mask M acts like MATLAB logical indexing.  If M(i,j)=1 then
-C(i,j) can be modified; if zero, it cannot be modified by the
-operation.
-

Static Methods for graph algorithms:

r = GrB.pagerank (A, opts) ;            % PageRank of a matrix
-C = GrB.ktruss (A, k, check) ;          % k-truss
-s = GrB.tricount (A, check) ;           % triangle count
-L = GrB.laplacian (A, type, check) ;    % Laplacian graph
-C = GrB.incidence (A, ...) ;            % incidence matrix
-[v, parent] = GrB.bfs (A, s, ...) ;     % breadth-first search
-iset = GrB.mis (A, check) ;             % maximal independent set
-Y = GrB.dnn (W, bias, Y0) ;             % deep neural network
-
More graph algorithms will be added in the future.
-

Thanks for watching!

Tim Davis, Texas A&M University, http://faculty.cse.tamu.edu/davis See also sparse, doc sparse, and https://twitter.com/DocSparse

graphblas_demo2