LAGraph context and error handling

The sections below describe a set of functions that manage the LAGraph context within a user application, and discuss how errors are handled.

LAGraph Context Functions

int LAGraph_Init(char *msg)

LAGraph_Init: initializes GraphBLAS and LAGraph. This method must be called before calling any other GrB* or LAGraph* method. It initializes GraphBLAS with GrB_init and then performs LAGraph-specific initializations. In particular, the LAGraph semirings listed below are created. GrB_init can also safely be called before calling LAGr_Init or LAGraph_Init.

Parameters

msg[inout] any error messages.

Returns

any GraphBLAS errors that may have been encountered.

Returns

  • GrB_SUCCESS – if successful.

  • GrB_INVALID_VALUE – if LAGraph_Init or LAGr_Init has already been called by the user application.

int LAGr_Init(GrB_Mode mode, void *(*user_malloc_function)(size_t), void *(*user_calloc_function)(size_t, size_t), void *(*user_realloc_function)(void*, size_t), void (*user_free_function)(void*), char *msg)

LAGr_Init: initializes GraphBLAS and LAGraph. LAGr_Init is identical to LAGraph_Init , except that it allows the user application to specify the GraphBLAS mode. It also provides four memory management functions, replacing the standard malloc, calloc, realloc, and free. The functions user_malloc_function, user_calloc_function, user_realloc_function, and user_free_function have the same signature as the ANSI C malloc, calloc, realloc, and free functions, respectively. Only user_malloc_function and user_free_function are required. user_calloc_function may be NULL, in which case LAGraph_Calloc uses LAGraph_Malloc and memset. Likewise, user_realloc_function may be NULL, in which case LAGraph_Realloc uses LAGraph_Malloc, memcpy, and LAGraph_Free.

Parameters
  • mode[in] the mode for GrB_Init

  • user_malloc_function[in] pointer to a malloc function

  • user_calloc_function[in] pointer to a calloc function, or NULL

  • user_realloc_function[in] pointer to a realalloc function, or NULL

  • user_free_function[in] pointer to a free function

  • msg[inout] any error messages.

Returns

any GraphBLAS errors that may have been encountered.

Returns

  • GrB_SUCCESS – if successful.

  • GrB_INVALID_VALUE – if LAGraph_Init or LAGr_Init has already been called by the user application.

  • GrB_NULL_POINTER – if user_malloc_function or user_free_function are NULL.

int LAGraph_Finalize(char *msg)

LAGraph_Finalize: finish LAGraph and GraphBLAS. Must be called as the last LAGraph method. It calls GrB_finalize and frees any LAGraph objects created by LAGraph_Init or LAGr_Init . After calling this method, no LAGraph or GraphBLAS methods may be used.

Parameters

msg[inout] any error messages.

Returns

any GraphBLAS errors that may have been encountered.

Returns

GrB_SUCCESS – if successful.

int LAGraph_Version(int version_number[3], char *version_date, char *msg)

LAGraph_Version: determines the version of LAGraph. The version number and date can also be obtained via compile-time constants from LAGraph.h. However, it is possible to compile a user application that #includes one version of LAGraph.h and then links with another version of the LAGraph library later on, so the version number and date may differ from the compile-time constants.

The LAGraph_Version method allows the library itself to be queried, after it is linked in with the user application.

The version_number array is set to LAGRAPH_VERSION_MAJOR, LAGRAPH_VERSION_MINOR, and LAGRAPH_VERSION_UPDATE, in that order. The LAGRAPH_DATE string is copied into the user-provided version_date string, and is null-terminated.

Parameters
  • version_number[out] an array of size 3; with the major, minor, and update versions of LAGraph, in that order.

  • version_date[out] an array of size >= LAGraph_MSG_LEN, returned with the date of this version of LAGraph.

  • msg[inout] any error messages.

Returns

  • GrB_SUCCESS – if successful.

  • GrB_NULL_POINTER – if version_number or version_date are NULL.

int LAGraph_GetNumThreads(int *nthreads_outer, int *nthreads_inner, char *msg)

LAGraph_GetNumThreads determines the current number of OpenMP threads that can be used. See LAGraph_SetNumThreads for a description of nthreads_outer and nthreads_inner.

Parameters
  • nthreads_outer[out] number of threads for outer region.

  • nthreads_inner[out] number of threads for inner region, or for the underlying GraphBLAS library.

  • msg[inout] any error messages.

Returns

  • GrB_SUCCESS – if successful.

  • GrB_NULL_POINTER – if nthreads_outer or nthreads_inner are NULL.

int LAGraph_SetNumThreads(int nthreads_outer, int nthreads_inner, char *msg)

LAGraph_SetNumThreads sets the current number of OpenMP threads that can be used by LAGraph and GraphBLAS. Two thread counts can be controlled:

Parameters
  • nthreads_outer[in] number of threads to be used in outer regions of a nested parallel construct assuming that nthreads_inner is used in the inner region. The total number of threads used for an entire nested region in LAGraph is given by nthreads_outer*nthreads_inner. This product is also the # of threads that a flat parallel region in LAGraph may use.

  • nthreads_inner[in] number of threads to be used in an inner region of a nested parallel construct, or for the # of threads to be used in each call to the underlying GraphBLAS library.

  • msg[inout] any error messages.

Returns

any GraphBLAS errors that may have been encountered.

Returns

GrB_SUCCESS – if successful.

Error handling

LAGRAPH_RETURN_VALUES

Nearly all LAGraph methods return an int to denote their status, and have a final string (msg) that captures any error messages.

LAGraph has a single function that does not follow this rule. LAGraph_WallClockTime has no error handling mechanism (it returns a value of type double, and does not have an final msg string parameter.

All other methods return an int to denote their status: zero if they are successful (which is the value of GrB_SUCCESS), negative on error, or positive for an informational value (such as GrB_NO_VALUE). Integers in the range -999 to 999 are reserved for GraphBLAS GrB_Info return values:

successful results:
  • GrB_SUCCESS = 0 // all is well

  • GrB_NO_VALUE = 1 // A(i,j) requested but not there

errors:
  • GrB_UNINITIALIZED_OBJECT = -1 // object has not been initialized

  • GrB_NULL_POINTER = -2 // input pointer is NULL

  • GrB_INVALID_VALUE = -3 // generic error; some value is bad

  • GrB_INVALID_INDEX = -4 // row or column index is out of bounds

  • GrB_DOMAIN_MISMATCH = -5 // object domains are not compatible

  • GrB_DIMENSION_MISMATCH = -6 // matrix dimensions do not match

  • GrB_OUTPUT_NOT_EMPTY = -7 // output matrix already has values

  • GrB_NOT_IMPLEMENTED = -8 // method not implemented

  • GrB_PANIC = -101 // unknown error

  • GrB_OUT_OF_MEMORY = -102 // out of memory

  • GrB_INSUFFICIENT_SPACE = -103, // output array not large enough

  • GrB_INVALID_OBJECT = -104 // object is corrupted

  • GrB_INDEX_OUT_OF_BOUNDS = -105 // row or col index out of bounds

  • GrB_EMPTY_OBJECT = -106 // an object does not contain a value

LAGraph returns any errors it receives from GraphBLAS, and also uses the GrB_* error codes in these cases:
  • GrB_INVALID_INDEX: if a source node id is out of range

  • GrB_INVALID_VALUE: if an enum to select an option is out of range

  • GrB_NOT_IMPLEMENTED: if a type is not supported, or when SuiteSparse GraphBLAS is required.

Summary of return values for all LAGraph functions that return int:

  • GrB_SUCCESS if successful

  • a negative GrB_Info value on error (in range -999 to -1)

  • a positive GrB_Info value if successful but with extra information (in range 1 to 999)

  • -1999 to -1000: a common LAGraph-specific error, see list above

  • 1000 to 1999: if successful, with extra LAGraph-specific information

  • <= -2000: an LAGraph error specific to a particular LAGraph method

  • >= 2000: an LAGraph warning specific to a particular LAGraph method

Many LAGraph methods share common error cases, described below. These return values are in the range -1000 to -1999. Return values of -2000 or greater may be used by specific LAGraph methods, which denote errors not in the following list:

  • LAGRAPH_INVALID_GRAPH (-1000):

    The input graph is invalid; the details are given in the error msg string returned by the method.

  • LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED (-1001):

    The method requires an undirected graph, or a directed graph with an adjacency matrix that is known to have a symmetric structure. LAGraph_Cached_IsSymmetricStructure can be used to determine this cached property.

  • LAGRAPH_IO_ERROR (-1002):

    A file input or output method failed, or an input file has an incorrect format that cannot be parsed.

  • LAGRAPH_NOT_CACHED (-1003):

    Some methods require one or more cached properties to be computed before calling them (AT, out_degree, or in_degree. Use LAGraph_Cached_AT, LAGraph_Cached_OutDegree, and/or LAGraph_Cached_InDegree to compute them.

  • LAGRAPH_NO_SELF_EDGES_ALLOWED (-1004):

    Some methods requires that the graph have no self edges, which correspond to the entries on the diagonal of the adjacency matrix. If the G->nself_edges cached property is nonzero or unknown, this error condition is returned. Use LAGraph_Cached_NSelfEdges to compute G->nself_edges, or LAGraph_DeleteSelfEdges to remove all diagonal entries from G->A.

  • LAGRAPH_CONVERGENCE_FAILURE (-1005):

    An iterative process failed to converge to a good solution.

  • LAGRAPH_CACHE_NOT_NEEDED (1000):

    This is a warning, not an error. It is returned by LAGraph_Cached_* methods when asked to compute cached properties that are not needed. These include G->AT and G->in_degree for an undirected graph.

LAGRAPH_MSG_LEN

All LAGraph functions (except for LAGraph_WallClockTime ) have a final msg parameter that is a pointer to a user-allocated string in which an algorithm-specific error message can be returned. If msg is NULL, no error message is returned. This is not itself an error condition, it just indicates that the caller does not need the message returned. If the message string is provided but no error occurs, an empty string is returned.

LAGRAPH_MSG_LEN is the minimum required length of a message string.

For example, the following call computes the breadth-first-search of an LAGraph_Graph G, starting at a given source node. It returns a status of zero if it succeeds and a negative value on failure.

 GrB_Vector level, parent ;
 char msg [LAGRAPH_MSG_LEN] ;
 int status = LAGr_BreadthFirstSearch (&level, &parent, G, src, msg) ;
 if (status < 0)
 {
     printf ("status %d, error: %s\n", status, msg) ;
     ... take corrective action here ...
 }

Error handling is simplified by the LAGRAPH_TRY / LAGRAPH_CATCH mechanism described below. For example, assuming the user application #defines a single LAGRAPH_CATCH mechanism for all error handling, the above example would become:

 GrB_Vector level, parent ;
 char msg [LAGRAPH_MSG_LEN] ;
 #define LAGRAPH_CATCH(status)                           \
 {                                                       \
     printf ("status %d, error: %s\n", status, msg) ;    \
     ... take corrective action here ...                 \
 }
 ...
 LAGRAPH_TRY (LAGr_BreadthFirstSearch (&level, &parent, G, src, msg)) ;

The advantage of the second use case is that the error-handling block of code needs to be written only once.

LAGRAPH_TRY(LAGraph_method)

LAGRAPH_TRY: try an LAGraph method and check for errors.

In a robust application, the return values from each call to LAGraph and GraphBLAS should be checked, and corrective action should be taken if an error occurs. The LAGRAPH_TRY and GRB_TRY macros assist in this effort.

LAGraph and GraphBLAS are written in C, and so they cannot rely on the try/catch mechanism of C++. To accomplish a similar goal, each LAGraph file must #define its own file-specific macro called LAGRAPH_CATCH. The typical usage of macro is to free any temporary matrices/vectors or workspace when an error occurs, and then “throw” the error by returning to the caller. A user application may also #define LAGRAPH_CATCH and use these macros. The LAGRAPH_CATCH macro takes a single argument, which is the return value from an LAGraph method.

A typical example of a user function that calls LAGraph might #define LAGRAPH_CATCH as follows. Suppose workvector is a GrB_vector used for computations internal to the mybfs function, and W is a (double *) space created by malloc.

 // an example user-defined LAGRAPH_CATCH macro, which prints the error
 // then frees any workspace or results, and returns to the caller:
 #define LAGRAPH_CATCH(status)                                   \
 {                                                               \
     printf ("LAGraph error: (%d): file: %s, line: %d\n%s\n",    \
         status, __FILE__, __LINE__, msg) ;                      \
     GrB_free (*parent) ;                                        \
     GrB_free (workvector) ;                                     \
     LAGraph_Free ((void **) &W, NULL) ;                         \
     return (status) ;                                           \
 }

 // an example user function that uses LAGRAPH_TRY / LAGRAPH_CATCH
 int mybfs (LAGraph_Graph G, GrB_Vector *parent, int64_t src)
 {
     GrB_Vector workvector = NULL ;
     double *W = NULL ;
     char msg [LAGRAPH_MSG_LEN] ;
     (*parent) = NULL ;
     LAGRAPH_TRY (LAGr_BreadthFirstSearch (NULL, parent, G, src, true,
         msg)) ;
     // ...
     return (GrB_SUCCESS) ;
 }

LAGRAPH_TRY is defined as follows:

 #define LAGRAPH_TRY(LAGraph_method)             \
 {                                               \
     int LG_status = LAGraph_method ;            \
     if (LG_status < GrB_SUCCESS)                \
     {                                           \
         LAGRAPH_CATCH (LG_status) ;             \
     }                                           \
 }

GRB_TRY(GrB_method)

GRB_TRY: LAGraph provides a similar functionality as LAGRAPH_TRY for calling GraphBLAS methods, with the GRB_TRY macro. GraphBLAS returns info = 0 (GrB_SUCCESS) or 1 (GrB_NO_VALUE) on success, and a value < 0 on failure. The user application must #define GRB_CATCH to use GRB_TRY.

GraphBLAS and LAGraph both use the convention that negative values are errors, and the LAGraph_status is a superset of the GrB_Info enum. As a result, the user can define LAGRAPH_CATCH and GRB_CATCH as the same operation. The main difference between the two would be the error message string. For LAGraph, the string is the last parameter, and LAGRAPH_CATCH can optionally print it out. For GraphBLAS, the GrB_error mechanism can return a string.

GRB_TRY is defined as follows:

 #define GRB_TRY(GrB_method)                     \
 {                                               \
     GrB_Info LG_GrB_Info = GrB_method ;         \
     if (LG_GrB_Info < GrB_SUCCESS)              \
     {                                           \
         GRB_CATCH (LG_GrB_Info) ;               \
     }                                           \
 }