1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
//------------------------------------------------------------------------------
// GB_Descriptor_get: get the status of a descriptor
//------------------------------------------------------------------------------
// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//------------------------------------------------------------------------------
// A descriptor modifies the behavoir of a GraphBLAS operation.
// This function is called via the GB_GET_DESCRIPTOR(...) macro.
// Descriptor field: Descriptor value:
// desc->out GxB_DEFAULT or GrB_REPLACE
// GrB_REPLACE means that the output matrix C is cleared just
// prior to writing results back into it, via C<M> = results. This
// descriptor does not affect how C is used to compute the results. If
// GxB_DEFAULT, then C is not cleared before doing C<M>=results.
// desc->mask GxB_DEFAULT, GrB_COMP, GrB_STRUCTURE, or
// GrB_COMP + GrB_STRUCTURE
// An optional 'write mask' defines how the results are to be written back
// into C. The boolean mask matrix M has the same size as C (M is
// typecasted to boolean if it has another type). If the M input to the
// GraphBLAS method is NULL, then implicitly M(i,j)=1 for all i and j.
// Let Z be the results to be written into C (the same dimension as C).
// If desc->mask is GxB_DEFAULT, and M(i,j)=1, then C(i,j) is over-written
// with Z(i,j). Otherwise, if M(i,j)=0 C(i,j) is left unmodified (it
// remains an implicit zero if it is so, or its value is unchanged if it
// has one). If desc->mask is GrB_COMP, then the use of M is negated:
// M(i,j)=0 means that C(i,j) is overwritten with Z(i,j), and M(i,j)=1
// means that C(i,j) is left unchanged. If the value is GrB_STRUCTURE,
// only the pattern is used; any entry present in the pattern has the
// value M(i,j)=1, and entries not in the pattern have the value M(i,j)=0.
// The GrB_COMP and GrB_STUCTURE options can be combined, as GrB_COMP +
// GrB_STRUCTURE.
// Writing results Z into C via the mask M is written as C<M>=Z in
// GraphBLAS notation.
// Note that it is the value of M(i,j) that determines how C(i,j) is
// overwritten. If the (i,j) entry is present in the M matrix data
// structure but has a numerical value of zero, then it is the same as if
// (i,j) is not present and thus implicitly zero. Both mean 'M(i,j)=0'
// in the description above of how the mask M works.
// desc->in0 and desc->in1 GxB_DEFAULT or GrB_TRAN
// A GrB_Matrix passed as an input parameter to GraphBLAS methods can
// optionally transpose them prior to using them. desc->in0 always refers
// to the first input to the method, and desc->in1 always refers to the
// second one.
// If the value of this descriptor is GxB_DEFAULT, then the matrix is used
// as-is. Otherwise, it is transposed first. That is, the results are
// the same as if the transpose of the matrix was passed to the method.
// desc->axb can be:
// GxB_DEFAULT = 0 automatic selection
// GxB_AxB_GUSTAVSON gather-scatter saxpy method
// GxB_AxB_HASH hash-based saxpy method
// GxB_AxB_SAXPY saxpy: either Gustavson or hash
// GxB_AxB_DOT dot product
// desc->do_sort true or false (default is false)
// desc->nthreads_max max # number of threads to use (auto if <= 0)
// desc->chunk chunk size for threadds
// These are copied from the GrB_Descriptor into the Context.
#include "GB.h"
GB_PUBLIC
GrB_Info GB_Descriptor_get // get the contents of a descriptor
(
const GrB_Descriptor desc, // descriptor to query, may be NULL
bool *C_replace, // if true replace C before C<M>=Z
bool *Mask_comp, // if true use logical negation of M
bool *Mask_struct, // if true use the structure of M
bool *In0_transpose, // if true transpose first input
bool *In1_transpose, // if true transpose second input
GrB_Desc_Value *AxB_method, // method for C=A*B
int *do_sort, // if nonzero, sort in GrB_mxm
GB_Context Context
)
{
//--------------------------------------------------------------------------
// check inputs
//--------------------------------------------------------------------------
// desc may be null, but if not NULL it must be initialized
GB_RETURN_IF_FAULTY (desc) ;
ASSERT (Context != NULL) ; // Context is always present
//--------------------------------------------------------------------------
// get the contents of the descriptor
//--------------------------------------------------------------------------
// default values if descriptor is NULL
GrB_Desc_Value C_desc = GxB_DEFAULT ;
GrB_Desc_Value Mask_desc = GxB_DEFAULT ;
GrB_Desc_Value In0_desc = GxB_DEFAULT ;
GrB_Desc_Value In1_desc = GxB_DEFAULT ;
GrB_Desc_Value AxB_desc = GxB_DEFAULT ;
int nthreads_desc = GxB_DEFAULT ;
double chunk_desc = GxB_DEFAULT ;
int do_sort_desc = GxB_DEFAULT ;
// non-defaults descriptor values
if (desc != NULL)
{
// get the contents
C_desc = desc->out ; // DEFAULT or REPLACE
Mask_desc = desc->mask ; // DEFAULT, COMP, STRUCTURE, or COMP+STRUCTURE
In0_desc = desc->in0 ; // DEFAULT or TRAN
In1_desc = desc->in1 ; // DEFAULT or TRAN
AxB_desc = desc->axb ; // DEFAULT, GUSTAVSON, HASH, or DOT
do_sort_desc = desc->do_sort ; // DEFAULT, or true (nonzero)
// default is zero. if descriptor->nthreads_max <= 0, GraphBLAS selects
// automatically: any value between 1 and the global nthreads_max. If
// descriptor->nthreads_max > 0, then that defines the exact number of
// threads to use in the current GraphBLAS operation.
nthreads_desc = desc->nthreads_max ;
chunk_desc = desc->chunk ;
}
// check for valid values of each descriptor field
if (!(C_desc == GxB_DEFAULT || C_desc == GrB_REPLACE) ||
!(Mask_desc == GxB_DEFAULT || Mask_desc == GrB_COMP ||
Mask_desc == GrB_STRUCTURE || Mask_desc == GrB_COMP+GrB_STRUCTURE) ||
!(In0_desc == GxB_DEFAULT || In0_desc == GrB_TRAN) ||
!(In1_desc == GxB_DEFAULT || In1_desc == GrB_TRAN) ||
!(AxB_desc == GxB_DEFAULT || AxB_desc == GxB_AxB_GUSTAVSON ||
AxB_desc == GxB_AxB_DOT ||
AxB_desc == GxB_AxB_HASH || AxB_desc == GxB_AxB_SAXPY))
{
return (GrB_INVALID_OBJECT) ;
}
if (C_replace != NULL)
{
*C_replace = (C_desc == GrB_REPLACE) ;
}
if (Mask_comp != NULL)
{
*Mask_comp = (Mask_desc == GrB_COMP)
|| (Mask_desc == GrB_COMP + GrB_STRUCTURE) ;
}
if (Mask_struct != NULL)
{
*Mask_struct = (Mask_desc == GrB_STRUCTURE)
|| (Mask_desc == GrB_STRUCTURE + GrB_COMP) ;
}
if (In0_transpose != NULL)
{
*In0_transpose = (In0_desc == GrB_TRAN) ;
}
if (In1_transpose != NULL)
{
*In1_transpose = (In1_desc == GrB_TRAN) ;
}
if (AxB_method != NULL)
{
*AxB_method = AxB_desc ;
}
if (do_sort != NULL)
{
*do_sort = do_sort_desc ;
}
// The number of threads is copied from the descriptor into the Context, so
// it is available to any internal function that needs it.
Context->nthreads_max = nthreads_desc ;
Context->chunk = chunk_desc ;
return (GrB_SUCCESS) ;
}
|