1 //------------------------------------------------------------------------------
2 // GB_matvec_build: check inputs and build a matrix or vector
3 //------------------------------------------------------------------------------
4 
5 // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
6 // SPDX-License-Identifier: Apache-2.0
7 
8 //------------------------------------------------------------------------------
9 
10 // CALLED BY: GrB_Matrix_build_* and GrB_Vector_build_*
11 // CALLS:     GB_build
12 
13 // This function implements GrB_Matrix_build_* and GrB_Vector_build_*.  It
14 // first constructs T by GB_builder as hypersparse, and GB_build conforms the
15 // result to the appropriate sparsity structure of C.
16 
17 #include "GB_build.h"
18 
GB_matvec_build(GrB_Matrix C,const GrB_Index * I,const GrB_Index * J,const void * X,const GrB_Index nvals,const GrB_BinaryOp dup,const GB_Type_code scode,const bool is_matrix,GB_Context Context)19 GrB_Info GB_matvec_build        // check inputs then build matrix or vector
20 (
21     GrB_Matrix C,               // matrix or vector to build
22     const GrB_Index *I,         // row indices of tuples
23     const GrB_Index *J,         // col indices of tuples (NULL for vector)
24     const void *X,              // array of values of tuples
25     const GrB_Index nvals,      // number of tuples
26     const GrB_BinaryOp dup,     // binary function to assemble duplicates
27     const GB_Type_code scode,   // GB_Type_code of X array
28     const bool is_matrix,       // true if C is a matrix, false if GrB_Vector
29     GB_Context Context
30 )
31 {
32 
33     //--------------------------------------------------------------------------
34     // check inputs
35     //--------------------------------------------------------------------------
36 
37     ASSERT_MATRIX_OK (C, "C for GB_matvec_build", GB0) ;
38 
39     GB_RETURN_IF_NULL (I) ;
40     if (I == GrB_ALL)
41     {
42         GB_ERROR (GrB_INVALID_VALUE, "List of row indices cannot be %s",
43             "GrB_ALL") ;
44     }
45 
46     if (nvals == GxB_RANGE || nvals == GxB_STRIDE || nvals == GxB_BACKWARDS)
47     {
48         GB_ERROR (GrB_INVALID_VALUE, "nvals cannot be %s",
49             "GxB_RANGE, GxB_STRIDE, or GxB_BACKWARDS") ;
50     }
51 
52     if (is_matrix)
53     {
54         GB_RETURN_IF_NULL (J) ;
55         if (J == GrB_ALL)
56         {
57             GB_ERROR (GrB_INVALID_VALUE, "List of column indices cannot be %s",
58                 "GrB_ALL") ;
59         }
60     }
61     else
62     {
63         // only GrB_Vector_build calls this function with J == NULL
64         ASSERT (J == NULL) ;
65     }
66 
67     GB_RETURN_IF_NULL (X) ;
68     GB_RETURN_IF_NULL_OR_FAULTY (dup) ;
69     if (GB_OP_IS_POSITIONAL (dup))
70     {
71         // dup operator cannot be a positional op
72         GB_ERROR (GrB_DOMAIN_MISMATCH,
73             "Positional op z=%s(x,y) not supported as dup op\n", dup->name) ;
74     }
75 
76     ASSERT_BINARYOP_OK (dup, "dup operator for assembling duplicates", GB0) ;
77     ASSERT (scode <= GB_UDT_code) ;
78 
79     if (nvals > GxB_INDEX_MAX)
80     {
81         // problem too large
82         GB_ERROR (GrB_INVALID_VALUE,
83             "Problem too large: nvals " GBu " exceeds " GBu,
84             nvals, GxB_INDEX_MAX) ;
85     }
86 
87     // check types of dup
88     if (dup->xtype != dup->ztype || dup->ytype != dup->ztype)
89     {
90         // all 3 types of z = dup (x,y) must be the same.  dup must also be
91         // associative but there is no way to check this in general.
92         GB_ERROR (GrB_DOMAIN_MISMATCH, "All domains of dup "
93             "operator for assembling duplicates must be identical.\n"
94             "operator is: [%s] = %s ([%s],[%s])",
95             dup->ztype->name, dup->name, dup->xtype->name, dup->ytype->name) ;
96     }
97 
98     if (!GB_Type_compatible (C->type, dup->ztype))
99     {
100         // the type of C and dup must be compatible
101         GB_ERROR (GrB_DOMAIN_MISMATCH,
102             "Operator [%s] for assembling duplicates has type [%s],\n"
103             "cannot be typecast to entries in output of type [%s]",
104             dup->name, dup->ztype->name, C->type->name) ;
105     }
106 
107     // C and X must be compatible
108     if (!GB_code_compatible (scode, dup->ztype->code))
109     {
110         // All types must be compatible with each other: C, dup, and X.
111         // User-defined types are only compatible with themselves; they are not
112         // compatible with any built-in type nor any other user-defined type.
113         // Thus, if C, dup, or X have any user-defined type, this
114         // condition requires all three types to be identical: the same
115         // user-defined type.  No casting will be done in this case.
116         GB_ERROR (GrB_DOMAIN_MISMATCH,
117             "Numerical values of tuples of type [%s]\n"
118             "cannot be typecast as input to the dup operator\n"
119             "z=%s(x,y), whose input types are [%s]",
120             GB_code_string (scode), dup->name, dup->ztype->name) ;
121     }
122 
123     if (!GB_IS_EMPTY (C))
124     {
125         // The matrix has existing entries.  This is required by the GraphBLAS
126         // API specification to generate an error, so the test is made here.
127         // However, any existing content is safely freed immediately below, so
128         // this test is not required, except to conform to the spec.  Zombies
129         // are excluded from this test.
130         GB_ERROR (GrB_OUTPUT_NOT_EMPTY,
131             "Output already has %s", "existing entries") ;
132     }
133 
134     //--------------------------------------------------------------------------
135     // build the matrix
136     //--------------------------------------------------------------------------
137 
138     // GB_build treats I, J, and X as read-only; they must not be modified
139 
140     return (GB_build (C, I, J, X, nvals, dup, scode, is_matrix,
141         /* true, */ Context)) ;
142 }
143 
144