1 //------------------------------------------------------------------------------
2 // GB_dense_subassign_21: C(:,:) = x where x is a scalar
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 // C(:,:) = x where C is a matrix and x is a scalar.
11
12 // C can have any sparsity on input; it is recreated as a full matrix, or left
13 // as bitmap. If C is bitmap, it is either left as bitmap, or converted to
14 // full if allowed by C->sparsity.
15
16 // If C is bitmap, GB_subassigner_method does not select this method directly.
17 // Instead, it selects GB_bitmap_assign, which then just calls this method
18 // via GB_bitmap_assign_noM_noaccum_whole.
19
20 // TODO::: create a uniform-valued matrix C instead
21
22 #include "GB_dense.h"
23 #include "GB_select.h"
24 #include "GB_Pending.h"
25 #include "GB_bitmap_assign_methods.h"
26
GB_dense_subassign_21(GrB_Matrix C,const void * scalar,const GrB_Type scalar_type,GB_Context Context)27 GrB_Info GB_dense_subassign_21 // C(:,:) = x, scalar to matrix assignment
28 (
29 GrB_Matrix C, // input/output matrix
30 const void *scalar, // input scalar
31 const GrB_Type scalar_type, // type of the input scalar
32 GB_Context Context
33 )
34 {
35
36 //--------------------------------------------------------------------------
37 // check inputs
38 //--------------------------------------------------------------------------
39
40 GrB_Info info ;
41 ASSERT_MATRIX_OK (C, "C for C(:,:)=x", GB0) ;
42 ASSERT (!GB_is_shallow (C)) ;
43 ASSERT (scalar != NULL) ;
44 // any prior pending tuples are discarded, and all zombies will be killed,
45 // so C can be anything on input.
46 ASSERT (GB_ZOMBIES_OK (C)) ;
47 ASSERT (GB_JUMBLED_OK (C)) ;
48 ASSERT (GB_PENDING_OK (C)) ;
49 ASSERT_TYPE_OK (scalar_type, "scalar_type for C(:,:)=x", GB0) ;
50
51 //--------------------------------------------------------------------------
52 // determine the number of threads to use
53 //--------------------------------------------------------------------------
54
55 int64_t cvdim = C->vdim ;
56 int64_t cvlen = C->vlen ;
57 GrB_Index cnzmax ;
58 bool ok = GB_Index_multiply (&cnzmax, cvlen, cvdim) ;
59 if (!ok)
60 {
61 // problem too large
62 return (GrB_OUT_OF_MEMORY) ;
63 }
64
65 GB_GET_NTHREADS_MAX (nthreads_max, chunk, Context) ;
66
67 //--------------------------------------------------------------------------
68 // typecast the scalar into the same type as C
69 //--------------------------------------------------------------------------
70
71 int64_t csize = C->type->size ;
72 GB_cast_function
73 cast_A_to_C = GB_cast_factory (C->type->code, scalar_type->code) ;
74 GB_void cwork [GB_VLA(csize)] ;
75 cast_A_to_C (cwork, scalar, scalar_type->size) ;
76
77 //--------------------------------------------------------------------------
78 // ensure C is full or bitmap
79 //--------------------------------------------------------------------------
80
81 // discard any prior pending tuples
82 GB_Pending_free (&(C->Pending)) ;
83
84 if (GB_IS_SPARSE (C) || GB_IS_HYPERSPARSE (C))
85 {
86 // clear prior content and recreate it; use exising header for C.
87 GB_phbix_free (C) ;
88 int C_sparsity = C->sparsity ; // save the sparsity control of C
89 bool C_static_header = C->static_header ;
90 info = GB_new_bix (&C, C_static_header, // full, old header
91 C->type, cvlen, cvdim, GB_Ap_null, C->is_csc,
92 GxB_FULL, true, C->hyper_switch, -1, cnzmax, true, Context) ;
93 if (info != GrB_SUCCESS)
94 {
95 // out of memory
96 return (GrB_OUT_OF_MEMORY) ;
97 }
98 C->magic = GB_MAGIC ;
99 C->nvec_nonempty = (cvlen == 0) ? 0 : cvdim ;
100 C->sparsity = C_sparsity ; // restore the sparsity control of C
101 }
102 else if (GB_IS_BITMAP (C))
103 {
104 // free the bitmap or set it to all ones
105 GB_bitmap_assign_to_full (C, nthreads_max) ;
106 }
107
108 //--------------------------------------------------------------------------
109 // C = x
110 //--------------------------------------------------------------------------
111
112 if (!GB_is_nonzero (cwork, csize))
113 {
114
115 //----------------------------------------------------------------------
116 // set all of C->x to zero
117 //----------------------------------------------------------------------
118
119 GB_memset (C->x, 0, cnzmax * csize, nthreads_max) ;
120
121 }
122 else
123 {
124
125 //----------------------------------------------------------------------
126 // define the worker for the switch factory
127 //----------------------------------------------------------------------
128
129 // TODO use type-punning to reduce # of case to 1, 2, 4, 8, 16 bytes
130
131 int64_t pC ;
132 int nthreads = GB_nthreads (cnzmax, chunk, nthreads_max) ;
133
134 // worker for built-in types
135 #define GB_WORKER(ctype) \
136 { \
137 ctype *restrict Cx = (ctype *) C->x ; \
138 ctype x = (*(ctype *) cwork) ; \
139 GB_PRAGMA (omp parallel for num_threads(nthreads) schedule(static))\
140 for (pC = 0 ; pC < cnzmax ; pC++) \
141 { \
142 Cx [pC] = x ; \
143 } \
144 } \
145 break ;
146
147 //----------------------------------------------------------------------
148 // launch the switch factory
149 //----------------------------------------------------------------------
150
151 switch (C->type->code)
152 {
153 case GB_BOOL_code : GB_WORKER (bool) ;
154 case GB_INT8_code : GB_WORKER (int8_t) ;
155 case GB_INT16_code : GB_WORKER (int16_t) ;
156 case GB_INT32_code : GB_WORKER (int32_t) ;
157 case GB_INT64_code : GB_WORKER (int64_t) ;
158 case GB_UINT8_code : GB_WORKER (uint8_t) ;
159 case GB_UINT16_code : GB_WORKER (uint16_t) ;
160 case GB_UINT32_code : GB_WORKER (uint32_t) ;
161 case GB_UINT64_code : GB_WORKER (uint64_t) ;
162 case GB_FP32_code : GB_WORKER (float) ;
163 case GB_FP64_code : GB_WORKER (double) ;
164 case GB_FC32_code : GB_WORKER (GxB_FC32_t) ;
165 case GB_FC64_code : GB_WORKER (GxB_FC64_t) ;
166 default:
167 {
168 // worker for all user-defined types
169 GB_BURBLE_N (cnzmax, "(generic C(:,:)=x assign) ") ;
170 GB_void *restrict Cx = (GB_void *) C->x ;
171 #pragma omp parallel for num_threads(nthreads) \
172 schedule(static)
173 for (pC = 0 ; pC < cnzmax ; pC++)
174 {
175 memcpy (Cx +((pC)*csize), cwork, csize) ;
176 }
177 }
178 break ;
179 }
180 }
181
182 //--------------------------------------------------------------------------
183 // return result
184 //--------------------------------------------------------------------------
185
186 ASSERT_MATRIX_OK (C, "C(:,:)=x output", GB0) ;
187 ASSERT (GB_IS_FULL (C) || GB_IS_BITMAP (C)) ;
188 ASSERT (!GB_ZOMBIES (C)) ;
189 ASSERT (!GB_JUMBLED (C)) ;
190 ASSERT (!GB_PENDING (C)) ;
191 return (GrB_SUCCESS) ;
192 }
193
194