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