Exemple #1
0
GrB_Info GB_Mask_compatible     // check type and dimensions of mask
(
    const GrB_Matrix Mask,      // mask to check
    const GrB_Matrix C,         // C<Mask>= ...
    const GrB_Index nrows,      // size of output if C is NULL (see GB*assign)
    const GrB_Index ncols,
    GB_Context Context
)
{ 

    ASSERT (GB_ALIAS_OK (C, Mask)) ;

    if (Mask != NULL)
    { 

        // Mask is typecast to boolean
        if (!GB_Type_compatible (Mask->type, GrB_BOOL))
        { 
            return (GB_ERROR (GrB_DOMAIN_MISMATCH, (GB_LOG,
                "Mask of type [%s] cannot be typecast to boolean",
                Mask->type->name))) ;
        }

        // check the Mask dimensions
        GrB_Index cnrows = (C == NULL) ? nrows : GB_NROWS (C) ;
        GrB_Index cncols = (C == NULL) ? ncols : GB_NCOLS (C) ;
        if (GB_NROWS (Mask) != cnrows || GB_NCOLS (Mask) != cncols)
        { 
            return (GB_ERROR (GrB_DIMENSION_MISMATCH, (GB_LOG,
                "Mask is "GBd"-by-"GBd"; "
                "does not match output dimensions ("GBu"-by-"GBu")",
                GB_NROWS (Mask), GB_NCOLS (Mask), cnrows, cncols))) ;
        }
    }

    return (GrB_SUCCESS) ;
}
Exemple #2
0
void GB_transpose_ix        // transpose the pattern and values of a matrix
(
    int64_t *Rp,            // size m+1, input: row pointers, shifted on output
    int64_t *Ri,            // size cnz, output column indices
    GB_void *Rx,            // size cnz, output numerical values, type R_type
    const GrB_Type R_type,  // type of output R (do typecasting into R)
    const GrB_Matrix A      // input matrix
)
{

    //--------------------------------------------------------------------------
    // check inputs
    //--------------------------------------------------------------------------

    ASSERT (A != NULL) ;
    ASSERT (R_type != NULL) ;
    ASSERT (Rp != NULL && Ri != NULL && Rx != NULL) ;
    ASSERT (GB_Type_compatible (A->type, R_type)) ;
    ASSERT (!GB_ZOMBIES (A)) ;

    //--------------------------------------------------------------------------
    // get the input matrix
    //--------------------------------------------------------------------------

    const int64_t *Ai = A->i ;
    const GB_void *Ax = A->x ;

    //--------------------------------------------------------------------------
    // define the worker for the switch factory
    //--------------------------------------------------------------------------

    #define GB_WORKER(rtype,atype)                              \
    {                                                           \
        rtype *rx = (rtype *) Rx ;                              \
        atype *ax = (atype *) Ax ;                              \
        GB_for_each_vector (A)                                  \
        {                                                       \
            GB_for_each_entry (j, p, pend)                      \
            {                                                   \
                int64_t q = Rp [Ai [p]]++ ;                     \
                Ri [q] = j ;                                    \
                /* rx [q] = ax [p], type casting */             \
                GB_CAST (rx [q], ax [p]) ;                      \
            }                                                   \
        }                                                       \
        return ;                                                \
    }

    //--------------------------------------------------------------------------
    // launch the switch factory
    //--------------------------------------------------------------------------

    // The switch factory cannot be disabled by #ifndef GBCOMPACT
    // because the generic worker does no typecasting.

    // switch factory for two types, controlled by code1 and code2
    GB_Type_code code1 = R_type->code ;         // defines rtype
    GB_Type_code code2 = A->type->code ;        // defines atype
    ASSERT (code1 <= GB_UDT_code) ;
    ASSERT (code2 <= GB_UDT_code) ;
    #include "GB_2type_template.c"

    //--------------------------------------------------------------------------
    // generic worker
    //--------------------------------------------------------------------------

    // the switch factory handles all built-in types; user-defined types
    // fall through the switch factory to here, which can never be
    // typecasted.  Because the generic worker does no typecasting, the
    // switch factory cannot be disabled.
    ASSERT (A->type == R_type && A->type->code > GB_FP64_code) ;

    int64_t asize = A->type->size ;
    GB_for_each_vector (A)
    {
        GB_for_each_entry (j, p, pend)
        { 
            int64_t q = Rp [Ai [p]]++ ;
            Ri [q] = j ;
            memcpy (Rx +(q*asize), Ax +(p*asize), asize) ;
        }
    }
Exemple #3
0
GrB_Info GB_emult           // C = A.*B
(
    GrB_Matrix *Chandle,    // output matrix (unallocated on input)
    const GrB_Type ctype,   // type of output matrix C
    const bool C_is_csc,    // format of output matrix C
    const GrB_Matrix A,     // input A matrix
    const GrB_Matrix B,     // input B matrix
    const GrB_BinaryOp op,  // op to perform C = op (A,B)
    GB_Context Context
)
{

    //--------------------------------------------------------------------------
    // check inputs
    //--------------------------------------------------------------------------

    ASSERT (Chandle != NULL) ;
    ASSERT_OK (GB_check (A, "A for C=A.*B", GB0)) ;
    ASSERT_OK (GB_check (B, "B for C=A.*B", GB0)) ;
    ASSERT (!GB_PENDING (A)) ; ASSERT (!GB_ZOMBIES (A)) ;
    ASSERT (!GB_PENDING (B)) ; ASSERT (!GB_ZOMBIES (B)) ;
    ASSERT_OK (GB_check (op, "op for C=A.*B", GB0)) ;
    ASSERT (A->vdim == A->vdim && B->vlen == A->vlen) ;

    ASSERT (GB_Type_compatible (ctype,   op->ztype)) ;
    ASSERT (GB_Type_compatible (A->type, op->xtype)) ;
    ASSERT (GB_Type_compatible (B->type, op->ytype)) ;

    (*Chandle) = NULL ;

    //--------------------------------------------------------------------------
    // allocate the output matrix C
    //--------------------------------------------------------------------------

    // C is hypersparse if A or B are hypersparse (contrast with GB_add)
    bool C_is_hyper = (A->is_hyper || B->is_hyper) && (A->vdim > 1) ;

    // [ allocate the result C; C->p is malloc'd
    // worst case nnz (C) is min (nnz (A), nnz (B))
    GrB_Info info ;
    GrB_Matrix C = NULL ;           // allocate a new header for C
    GB_CREATE (&C, ctype, A->vlen, A->vdim, GB_Ap_malloc, C_is_csc,
        GB_SAME_HYPER_AS (C_is_hyper), B->hyper_ratio,
        GB_IMIN (A->nvec_nonempty, B->nvec_nonempty),
        GB_IMIN (GB_NNZ (A), GB_NNZ (B)), true) ;
    if (info != GrB_SUCCESS)
    { 
        return (info) ;
    }

    //--------------------------------------------------------------------------
    // get functions and type sizes
    //--------------------------------------------------------------------------

    GB_cast_function cast_A_to_X, cast_B_to_Y, cast_Z_to_C ;

    cast_A_to_X = GB_cast_factory (op->xtype->code, A->type->code) ;
    cast_B_to_Y = GB_cast_factory (op->ytype->code, B->type->code) ;
    cast_Z_to_C = GB_cast_factory (C->type->code,   op->ztype->code) ;

    // If types are user-defined, the cast* function is just
    // GB_copy_user_user, which requires the size of the type.  No typecast is
    // done.

    GxB_binary_function fmult = op->function ;

    size_t xsize = op->xtype->size ;
    size_t ysize = op->ytype->size ;
    size_t zsize = op->ztype->size ;
    size_t asize = A->type->size ;
    size_t bsize = B->type->size ;
    size_t csize = C->type->size ;

    // no typecasting needed if all the types match the operator
    bool nocasting =
        (A->type->code == op->xtype->code) &&
        (B->type->code == op->ytype->code) &&
        (C->type->code == op->ztype->code) ;

    // scalar workspace
    char xwork [nocasting ? 1 : xsize] ;
    char ywork [nocasting ? 1 : ysize] ;
    char zwork [nocasting ? 1 : zsize] ;

    //--------------------------------------------------------------------------
    // C = A .* B, where .*+ is defined by z=fmult(x,y)
    //--------------------------------------------------------------------------

    int64_t *Ci = C->i ;
    GB_void *Cx = C->x ;

    int64_t jlast, cnz, cnz_last ;
    GB_jstartup (C, &jlast, &cnz, &cnz_last) ;

    const int64_t *Ai = A->i, *Bi = B->i ;
    const GB_void *Ax = A->x, *Bx = B->x ;

    GB_for_each_vector2 (A, B)
    {

        //----------------------------------------------------------------------
        // get the next column, A (:,j) and B (:j)
        //----------------------------------------------------------------------

        int64_t GBI2_initj (Iter, j, pa, pa_end, pb, pb_end) ;
        int64_t ajnz = pa_end - pa ;
        int64_t bjnz = pb_end - pb ;

        //----------------------------------------------------------------------
        // compute C (:,j): pattern is the set intersection
        //----------------------------------------------------------------------

        if (ajnz == 0 || bjnz == 0)
        { 

            // one or both columns are empty; set intersection is empty
            ;

        }
        else if (Ai [pa_end-1] < Bi [pb])
        { 

            // all entries in A are in lower row indices than all the
            // entries in B; set intersection is empty
            ;

        }
        else if (Bi [pb_end-1] < Ai [pa])
        { 
            // all entries in B are in lower row indices than all the
            // entries in A; set intersection is empty
            ;

        }
        else if (ajnz > 256 * bjnz)
        {

            //------------------------------------------------------------------
            // A (:,j) has many more nonzeros than B (:,j)
            //------------------------------------------------------------------

            for ( ; pa < pa_end && pb < pb_end ; )
            {
                int64_t ia = Ai [pa] ;
                int64_t ib = Bi [pb] ;
                if (ia < ib)
                { 
                    // A (ia,j) appears before B (ib,j)
                    // discard all entries A (ia:ib-1,j)
                    int64_t pleft = pa + 1 ;
                    int64_t pright = pa_end ;
                    GB_BINARY_TRIM_SEARCH (ib, Ai, pleft, pright) ;
                    ASSERT (pleft > pa) ;
                    pa = pleft ;
                }
                else if (ia > ib)
                { 
                    // B (ib,j) appears before A (ia,j)
                    pb++ ;
                }
                else // ia == ib
                { 
                    // A (i,j) and B (i,j) match
                    GB_EMULT ;
                }
            }

        }
        else if (bjnz > 256 * ajnz)
        {

            //------------------------------------------------------------------
            // B (:,j) has many more nonzeros than A (:,j)
            //------------------------------------------------------------------

            for ( ; pa < pa_end && pb < pb_end ; )
            {
                int64_t ia = Ai [pa] ;
                int64_t ib = Bi [pb] ;
                if (ia < ib)
                { 
                    // A (ia,j) appears before B (ib,j)
                    pa++ ;
                }
                else if (ia > ib)
                { 
                    // B (ib,j) appears before A (ia,j)
                    // discard all entries B (ib:ia-1,j)
                    int64_t pleft = pb + 1 ;
                    int64_t pright = pb_end ;
                    GB_BINARY_TRIM_SEARCH (ia, Bi, pleft, pright) ;
                    ASSERT (pleft > pb) ;
                    pb = pleft ;
                }
                else // ia == ib
                { 
                    // A (i,j) and B (i,j) match
                    GB_EMULT ;
                }
            }

        }
        else
        {

            //------------------------------------------------------------------
            // A (:,j) and B (:,j) have about the same number of entries
            //------------------------------------------------------------------

            for ( ; pa < pa_end && pb < pb_end ; )
            {
                int64_t ia = Ai [pa] ;
                int64_t ib = Bi [pb] ;
                if (ia < ib)
                { 
                    // A (ia,j) appears before B (ib,j)
                    pa++ ;
                }
                else if (ia > ib)
                { 
                    // B (ib,j) appears before A (ia,j)
                    pb++ ;
                }
                else // ia == ib
                { 
                    // A (i,j) and B (i,j) match
                    GB_EMULT ;
                }
            }
        }

        //----------------------------------------------------------------------
        // finalize C(:,j)
        //----------------------------------------------------------------------

        // this cannot fail since C->plen is the upper bound: min of the
        // non-empty vectors of A and B
        info = GB_jappend (C, j, &jlast, cnz, &cnz_last, Context) ;
        ASSERT (info == GrB_SUCCESS) ;

        #if 0
        // if it could fail, do this:
        if (info != GrB_SUCCESS) { GB_MATRIX_FREE (&C) ; return (info) ; }
        #endif
    }
Exemple #4
0
GrB_Info GB_user_build          // check inputs then build matrix
(
    GrB_Matrix C,               // matrix to build
    const GrB_Index *I,         // row indices of tuples
    const GrB_Index *J,         // col indices of tuples
    const void *S,              // array of values of tuples
    const GrB_Index nvals,      // number of tuples
    const GrB_BinaryOp dup,     // binary function to assemble duplicates
    const GB_Type_code scode,   // GB_Type_code of S array
    const bool is_matrix,       // true if C is a matrix, false if GrB_Vector
    GB_Context Context
)
{

    //--------------------------------------------------------------------------
    // check inputs
    //--------------------------------------------------------------------------

    ASSERT_OK (GB_check (C, "C for GB_user_build", GB0)) ;
    GB_RETURN_IF_NULL (I) ;
    if (I == GrB_ALL)
    { 
        return (GB_ERROR (GrB_INVALID_VALUE, (GB_LOG,
            "List of row indices cannot be GrB_ALL"))) ;
    }

    if (nvals == GxB_RANGE || nvals == GxB_STRIDE || nvals == GxB_BACKWARDS)
    { 
        return (GB_ERROR (GrB_INVALID_VALUE, (GB_LOG,
            "nvals cannot be GxB_RANGE, GxB_STRIDE, or GxB_BACKWARDS"))) ;
    }

    if (is_matrix)
    {
        GB_RETURN_IF_NULL (J) ;
        if (J == GrB_ALL)
        { 
            return (GB_ERROR (GrB_INVALID_VALUE, (GB_LOG,
                "List of column indices cannot be 'GrB_ALL'"))) ;
        }
    }
    else
    { 
        // only GrB_Vector_build calls this function with J == NULL
        ASSERT (J == NULL) ;
    }

    GB_RETURN_IF_NULL (S) ;
    GB_RETURN_IF_NULL_OR_FAULTY (dup) ;

    ASSERT_OK (GB_check (dup, "dup operator for assembling duplicates", GB0)) ;
    ASSERT (scode <= GB_UDT_code) ;

    if (nvals > GB_INDEX_MAX)
    { 
        // problem too large
        return (GB_ERROR (GrB_INVALID_VALUE, (GB_LOG,
            "problem too large: nvals "GBu" exceeds "GBu,
            nvals, GB_INDEX_MAX))) ;
    }

    // check types of dup
    if (dup->xtype != dup->ztype || dup->ytype != dup->ztype)
    { 
        // all 3 types of z = dup (x,y) must be the same.  dup must also be
        // associative but there is no way to check this in general.
        return (GB_ERROR (GrB_DOMAIN_MISMATCH, (GB_LOG, "All domains of dup "
        "operator for assembling duplicates must be identical.\n"
        "operator is: [%s] = %s ([%s],[%s])",
        dup->ztype->name, dup->name, dup->xtype->name, dup->ytype->name))) ;
    }

    if (!GB_Type_compatible (C->type, dup->ztype))
    { 
        // the type of C and dup must be compatible
        return (GB_ERROR (GrB_DOMAIN_MISMATCH, (GB_LOG,
        "operator dup [%s] has type [%s]\n"
        "cannot be typecast to entries in output of type [%s]",
        dup->name, dup->ztype->name, C->type->name))) ;
    }

    // C and S must be compatible
    if (!GB_code_compatible (scode, dup->ztype->code))
    { 
        // All types must be compatible with each other: C, dup, and S.
        // User-defined types are only compatible with themselves; they are not
        // compatible with any built-in type nor any other user-defined type.
        // Thus, if C, dup, or S have any user-defined type, this
        // condition requires all three types to be identical: the same
        // user-defined type.  No casting will be done in this case.
        return (GB_ERROR (GrB_DOMAIN_MISMATCH, (GB_LOG,
        "numerical values of tuples of type [%s]\n"
        "cannot be typecast as input to the dup operator\n"
        "z=%s(x,y), whose input types are [%s]",
        GB_code_string (scode), dup->name, dup->ztype->name))) ;
    }

    if (!GB_EMPTY (C))
    { 
        // The matrix has existing entries.  This is required by the GraphBLAS
        // API specification to generate an error, so the test is made here.
        // However, any existing content is safely freed immediately below, so
        // this test is not required, except to conform to the spec.  Zombies
        // are excluded from this test.
        return (GB_ERROR (GrB_OUTPUT_NOT_EMPTY, (GB_LOG,
            "output already has existing entries"))) ;
    }

    //--------------------------------------------------------------------------
    // build the matrix
    //--------------------------------------------------------------------------

    return (GB_build (C, I, J, S, nvals, dup, scode, is_matrix, true, Context));
}