1 //------------------------------------------------------------------------------
2 // GB_subassigner_method: determine method for GB_subassign
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 #include "GB_subassign.h"
11 
GB_subassigner_method(const GrB_Matrix C,const bool C_replace,const GrB_Matrix M,const bool Mask_comp,const bool Mask_struct,const GrB_BinaryOp accum,const GrB_Matrix A,const int Ikind,const int Jkind,const bool scalar_expansion)12 int GB_subassigner_method           // return method to use in GB_subassigner
13 (
14     const GrB_Matrix C,             // input/output matrix for results
15     const bool C_replace,           // C matrix descriptor
16     const GrB_Matrix M,             // optional mask for C(I,J), unused if NULL
17     const bool Mask_comp,           // mask descriptor
18     const bool Mask_struct,         // if true, use the only structure of M
19     const GrB_BinaryOp accum,       // optional accum for Z=accum(C(I,J),A)
20     const GrB_Matrix A,             // input matrix (NULL for scalar expansion)
21     const int Ikind,
22     const int Jkind,
23     const bool scalar_expansion     // if true, expand scalar to A
24 )
25 {
26 
27     //--------------------------------------------------------------------------
28     // check mask conditions
29     //--------------------------------------------------------------------------
30 
31     #ifdef GB_DEBUG
32     // empty_mask: mask not present and complemented.  This condition has
33     // already handled by GB_assign_prep.
34     bool empty_mask = (M == NULL) && Mask_comp ;
35     ASSERT (!empty_mask) ;
36     #endif
37 
38     // no_mask: mask not present and not complemented
39     bool no_mask = (M == NULL) && !Mask_comp ;
40 
41     // GB_assign_prep has already disabled C_replace if no mask present
42     ASSERT (GB_IMPLIES (no_mask, !C_replace)) ;
43 
44     bool M_is_bitmap = GB_IS_BITMAP (M) ;
45 
46     //--------------------------------------------------------------------------
47     // check if C is empty
48     //--------------------------------------------------------------------------
49 
50     bool C_is_empty = (GB_NNZ (C) == 0 && !GB_PENDING (C) && !GB_ZOMBIES (C)) ;
51 
52     // if C is empty, C_replace is effectively false and already disabled
53     ASSERT (GB_IMPLIES (C_is_empty, !C_replace)) ;
54 
55     //--------------------------------------------------------------------------
56     // check if A is dense; a scalar is an implicit dense matrix, or bitmap
57     //--------------------------------------------------------------------------
58 
59     bool A_is_bitmap = GB_IS_BITMAP (A) ;
60 
61     //--------------------------------------------------------------------------
62     // determine the method to use
63     //--------------------------------------------------------------------------
64 
65     // whole_C_matrix is true if all of C(:,:) is being assigned to
66     bool whole_C_matrix = (Ikind == GB_ALL) && (Jkind == GB_ALL) ;
67 
68     bool C_splat_scalar = false ;   // C(:,:) = x
69     bool C_splat_matrix = false ;   // C(:,:) = A
70 
71     if (whole_C_matrix && no_mask && (accum == NULL))
72     {
73 
74         //----------------------------------------------------------------------
75         // C(:,:) = x or A:  whole matrix assignment with no mask
76         //----------------------------------------------------------------------
77 
78         if (scalar_expansion)
79         {
80             // Method 21: C(:,:) = x
81             C_splat_scalar = true ;
82         }
83         else
84         {
85             // Method 24: C(:,:) = A
86             C_splat_matrix = true ;
87         }
88     }
89 
90     // check if C is competely dense:  all entries present and no pending work.
91     bool C_is_bitmap = GB_IS_BITMAP (C) ;
92     bool C_as_if_full = GB_as_if_full (C) ;
93     bool C_dense_update = false ;
94     if (C_as_if_full)
95     {
96         // C is dense with no pending work
97         if (whole_C_matrix && no_mask && (accum != NULL)
98             && (C->type == accum->ztype) && (C->type == accum->xtype))
99         {
100             // C(:,:) += x or A, where C is dense, no typecasting of C
101             C_dense_update = true ;
102         }
103     }
104 
105     // simple_mask: C(I,J)<M> = ... ; or C(I,J)<M> += ...
106     bool simple_mask = (!C_replace && M != NULL && !Mask_comp) ;
107 
108     // C_Mask_scalar: C(I,J)<M> = scalar or += scalar
109     bool C_Mask_scalar = (scalar_expansion && simple_mask) ;
110 
111     // C_Mask_matrix:  C(I,J)<M> = A or += A
112     bool C_Mask_matrix = (!scalar_expansion && simple_mask) ;
113 
114     bool S_Extraction ;
115     bool method_06d = false ;
116     bool method_25 = false ;
117 
118     if (C_splat_scalar)
119     {
120         // Method 21: C(:,:) = x where x is a scalar; C becomes dense
121         S_Extraction = false ;
122     }
123     else if (C_splat_matrix)
124     {
125         // Method 24: C(:,:) = A
126         S_Extraction = false ;
127     }
128     else if (C_dense_update)
129     {
130         // Methods 22 and 23: C(:,:) += x or A where C is dense
131         S_Extraction = false ;
132     }
133     else if (C_Mask_scalar)
134     {
135         // Method 05*, or 07: C(I,J)<M> = or += scalar; C_replace false
136         S_Extraction = false ;
137     }
138     else if (C_Mask_matrix)
139     {
140         // C(I,J)<M> = A or += A
141         if (accum != NULL)
142         {
143             // Method 08n: C(I,J)<M> += A, no S.  Cannot use M or A as bitmap.
144             // Method 08s: C(I,J)<M> += A, with S.  Can use M or A as bitmap.
145             // if S_Extraction is true, Method 08s is used (with S).
146             // Method 08n is not used if any matrix is bitmap.
147             // If C is bitmap, GB_bitmap_assign_M_accum is used instead.
148             S_Extraction = M_is_bitmap || A_is_bitmap ;
149         }
150         else
151         {
152             // C(I,J)<M> = A ;  use 06s (with S) or 06n (without S)
153             // method 06s (with S) is faster when nnz (A) < nnz (M).
154             if ((C_as_if_full || C_is_bitmap) && whole_C_matrix && M == A)
155             {
156                 // Method 06d: C<A> = A
157                 method_06d = true ;
158                 S_Extraction = false ;
159             }
160             else if (C_is_empty && whole_C_matrix && Mask_struct &&
161                 (scalar_expansion || GB_as_if_full (A) || A_is_bitmap))
162             {
163                 // Method 25: C<M,s> = A, where M is structural, A is
164                 // dense, and C starts out empty.  The pattern of C will be the
165                 // same as M, and the subassign method is extremely simple.
166                 method_25 = true ;
167                 S_Extraction = false ;
168             }
169             else
170             {
171                 // Method 06n (no S) or Method 06s (with S):
172                 // Method 06n is not used if M or A are bitmap.  If M and A are
173                 // aliased and Method 06d is not used, then 06s is used instead
174                 // of 06n since M==A implies nnz(A) == nnz(M).
175                 S_Extraction = (GB_NNZ (A) < GB_NNZ (M))
176                     || M_is_bitmap || A_is_bitmap ;
177             }
178         }
179     }
180     else
181     {
182         // all other methods require S
183         S_Extraction = true ;
184     }
185 
186     //==========================================================================
187     // submatrix assignment C(I,J)<M> = accum (C(I,J),A): meta-algorithm
188     //==========================================================================
189 
190     // There are up to 128 combinations of options, but not all must be
191     // implemented, because they are either identical to another method
192     // (C_replace is effectively false if M=NULL and Mask_comp=false), or they
193     // are not used (the last option, whether or not S is constructed, is
194     // determined here; it is not a user input).  The first 5 options are
195     // determined by the input.  The table below has been pruned to remove
196     // combinations that are not used, or equivalent to other entries in the
197     // table.  Only 22 unique combinations of the 128 combinations are needed,
198     // with additional special cases when C(:,:) is dense.
199 
200     //      M           present or NULL
201     //      Mask_comp   true or false
202     //      Mask_struct structural or valued mask
203     //      C_replace   true or false
204     //      accum       present or NULL
205     //      A           scalar (x) or matrix (A)
206     //      S           constructed or not
207 
208     // C(I,J)<(M,comp,repl)> ( = , += ) (A, scalar), (with or without S);
209     // I and J can be anything for any of these methods (":", colon, or list).
210 
211     // See the "No work to do..." comment above:
212     // If M is not present, Mask_comp true, C_replace false: no work to do.
213     // If M is not present, Mask_comp true, C_replace true: use Method 00
214     // If M is not present, Mask_comp false:  C_replace is now false.
215 
216         //  =====================       ==============
217         //  M   cmp rpl acc A   S       method: action
218         //  =====================       ==============
219 
220         //  -   -   x   -   -   -       21:  C = x, no S, C anything
221         //  -   -   x   -   A   -       24:  C = A, no S, C and A anything
222         //  -   -   -   +   -   -       22:  C += x, no S, C dense
223         //  -   -   -   +   A   -       23:  C += A, no S, C dense
224 
225         //  -   -   -   -   -   S       01:  C(I,J) = x, with S
226         //  -   -   -   -   A   S       02:  C(I,J) = A, with S
227         //  -   -   -   +   -   S       03:  C(I,J) += x, with S
228         //  -   -   -   +   A   S       04:  C(I,J) += A, with S
229         //  -   -   r                        uses methods 01, 02, 03, 04
230         //  -   c   -                        no work to do
231         //  -   c   r           S       00:  C(I,J)<!,repl> = empty, with S
232 
233         //  M   -   -   -   -   -       05d: C<M> = x, no S, C dense
234         //  M   -   -   -   -   -       05e: C<M,s> = x, no S, C empty
235         //  M   -   -   -   -   -       05f: C<C,s> = x, no S, C == M
236         //  M   -   -   -   -   -       05:  C(I,J)<M> = x, no S
237         //  A   -   -   -   A   -       06d: C<A> = A, no S, C dense
238         //  M   -   -   -   A   -       25:  C<M,s> = A, A dense, C empty
239         //  M   -   -   -   A   -       06n: C(I,J)<M> = A, no S
240         //  M   -   -   -   A   S       06s: C(I,J)<M> = A, with S
241         //  M   -   -   +   -   -       07:  C(I,J)<M> += x, no S
242         //  M   -   -   +   A   -       08n: C(I,J)<M> += A, no S
243         //  M   -   -   +   A   -       08s: C(I,J)<M> += A, with S
244         //  M   -   r   -   -   S       09:  C(I,J)<M,repl> = x, with S
245         //  M   -   r   -   A   S       10:  C(I,J)<M,repl> = A, with S
246         //  M   -   r   +   -   S       11:  C(I,J)<M,repl> += x, with S
247         //  M   -   r   +   A   S       12:  C(I,J)<M,repl> += A, with S
248 
249         //  M   c   -   -   -   S       13:  C(I,J)<!M> = x, with S
250         //  M   c   -   -   A   S       14:  C(I,J)<!M> = A, with S
251         //  M   c   -   +   -   S       15:  C(I,J)<!M> += x, with S
252         //  M   c   -   +   A   S       16:  C(I,J)<!M> += A, with S
253         //  M   c   r   -   -   S       17:  C(I,J)<!M,repl> = x, with S
254         //  M   c   r   -   A   S       18:  C(I,J)<!M,repl> = A, with S
255         //  M   c   r   +   -   S       19:  C(I,J)<!M,repl> += x, with S
256         //  M   c   r   +   A   S       20:  C(I,J)<!M,repl> += A, with S
257 
258         //----------------------------------------------------------------------
259         // FUTURE::: 8 simpler cases when I and J are ":" (S not needed):
260         //----------------------------------------------------------------------
261 
262         //  M   -   -   -   A   -       06x: C(:,:)<M> = A
263         //  M   -   -   +   A   -       08x: C(:,:)<M> += A
264         //  M   -   r   -   A   -       10x: C(:,:)<M,repl> = A
265         //  M   -   r   +   A   -       12x: C(:,:)<M,repl> += A
266         //  M   c   -   -   A   -       14x: C(:,:)<!M> = A
267         //  M   c   -   +   A   -       16x: C(:,:)<!M> += A
268         //  M   c   r   -   A   -       18x: C(:,:)<!M,repl> = A
269         //  M   c   r   +   A   -       20x: C(:,:)<!M,repl> += A
270 
271         //----------------------------------------------------------------------
272         // FUTURE::: C<C,s> += x   C == M, update all values, C_replace ignored
273         // FUTURE::: C<C,s> = A    C == M, A dense, C_replace ignored
274         //----------------------------------------------------------------------
275 
276     // For the single case C(I,J)<M>=A, two methods can be used: 06n and 06s.
277 
278     int subassign_method = -1 ;
279 
280     if (C_splat_scalar)
281     {
282 
283         //----------------------------------------------------------------------
284         // C = x where x is a scalar; C becomes full
285         //----------------------------------------------------------------------
286 
287         //  =====================       ==============
288         //  M   cmp rpl acc A   S       method: action
289         //  =====================       ==============
290 
291         //  -   -   x   -   -   -       21:  C = x, no S, C anything
292 
293         ASSERT (whole_C_matrix) ;           // C(:,:) is modified
294         ASSERT (M == NULL) ;                // no mask present
295         ASSERT (accum == NULL) ;            // accum is not present
296         ASSERT (!C_replace) ;               // C_replace is effectively false
297         ASSERT (!S_Extraction) ;            // S is not used
298         ASSERT (scalar_expansion) ;         // x is a scalar
299 
300         // Method 21: C = x where x is a scalar; C becomes full
301         subassign_method = GB_SUBASSIGN_METHOD_21 ;
302 
303     }
304     else if (C_splat_matrix)
305     {
306 
307         //----------------------------------------------------------------------
308         // C = A
309         //----------------------------------------------------------------------
310 
311         //  =====================       ==============
312         //  M   cmp rpl acc A   S       method: action
313         //  =====================       ==============
314 
315         //  -   -   x   -   A   -       24:  C = A, no S, C and A anything
316 
317         ASSERT (whole_C_matrix) ;           // C(:,:) is modified
318         ASSERT (M == NULL) ;                // no mask present
319         ASSERT (accum == NULL) ;            // accum is not present
320         ASSERT (!C_replace) ;               // C_replace is effectively false
321         ASSERT (!S_Extraction) ;            // S is not used
322         ASSERT (!scalar_expansion) ;        // A is a matrix
323 
324         // Method 24: C = A
325         subassign_method = GB_SUBASSIGN_METHOD_24 ;
326 
327     }
328     else if (C_dense_update)
329     {
330 
331         //----------------------------------------------------------------------
332         // C += A or x where C is dense or full (and becomes full)
333         //----------------------------------------------------------------------
334 
335         //  =====================       ==============
336         //  M   cmp rpl acc A   S       method: action
337         //  =====================       ==============
338         //  -   -   -   +   -   -       22:  C += x, no S, C dense
339         //  -   -   -   +   A   -       23:  C += A, no S, C dense
340 
341         ASSERT (C_as_if_full) ;             // C is dense
342         ASSERT (whole_C_matrix) ;           // C(:,:) is modified
343         ASSERT (M == NULL) ;                // no mask present
344         ASSERT (accum != NULL) ;            // accum is present
345         ASSERT (!C_replace) ;               // C_replace is false
346         ASSERT (!S_Extraction) ;            // S is not used
347 
348         if (scalar_expansion)
349         {
350             // Method 22: C(:,:) += x where C is dense or full
351             subassign_method = GB_SUBASSIGN_METHOD_22 ;
352         }
353         else
354         {
355             // Method 23: C(:,:) += A where C is dense or full
356             subassign_method = GB_SUBASSIGN_METHOD_23 ;
357         }
358 
359     }
360     else if (C_Mask_scalar)
361     {
362 
363         //----------------------------------------------------------------------
364         // C(I,J)<M> = scalar or +=scalar
365         //----------------------------------------------------------------------
366 
367         //  =====================       ==============
368         //  M   cmp rpl acc A   S       method: action
369         //  =====================       ==============
370         //  M   -   -   -   -   -       05d: C(:,:)<M> = x, no S, C dense
371         //  M   -   -   -   -   -       05e: C(:,:)<M,s> = x, no S, C empty
372         //  M   -   -   -   -   -       05f: C(:,:)<C,s> = x, no S, C == M
373         //  M   -   -   -   -   -       05:  C(I,J)<M> = x, no S
374         //  M   -   -   +   -   -       07:  C(I,J)<M> += x, no S
375 
376         ASSERT (scalar_expansion) ;         // A is a scalar
377         ASSERT (M != NULL && !Mask_comp) ;  // mask M present, not compl.
378         ASSERT (!C_replace) ;               // C_replace is false
379         ASSERT (!S_Extraction) ;            // S is not used
380 
381         if (accum == NULL)
382         {
383             if (C == M && whole_C_matrix && Mask_struct)
384             {
385                 // Method 05f: C(:,:)<C,s> = scalar ; no S ; C == M ; M struct
386                 subassign_method = GB_SUBASSIGN_METHOD_05f ;
387             }
388             else if (C_is_empty && whole_C_matrix && Mask_struct)
389             {
390                 // Method 05e: C(:,:)<M,s> = scalar ; no S; C empty, M struct
391                 subassign_method = GB_SUBASSIGN_METHOD_05e ;
392             }
393             else if (C_as_if_full && whole_C_matrix)
394             {
395                 // Method 05d: C(:,:)<M> = scalar ; no S; C is dense or full;
396                 // C becomes full.
397                 subassign_method = GB_SUBASSIGN_METHOD_05d ;
398             }
399             else
400             {
401                 // Method 05: C(I,J)<M> = scalar ; no S
402                 subassign_method = GB_SUBASSIGN_METHOD_05 ;
403             }
404         }
405         else
406         {
407             // Method 07: C(I,J)<M> += scalar ; no S
408             subassign_method = GB_SUBASSIGN_METHOD_07 ;
409         }
410 
411     }
412     else if (C_Mask_matrix)
413     {
414 
415         //----------------------------------------------------------------------
416         // C(I,J)<M> = A or += A
417         //----------------------------------------------------------------------
418 
419         //  =====================       ==============
420         //  M   cmp rpl acc A   S       method: action
421         //  =====================       ==============
422         //  M   -   -   +   A   -       08n:  C(I,J)<M> += A, no S
423         //  M   -   -   +   A   -       08s:  C(I,J)<M> += A, with S
424         //  A   -   -   -   A   -       06d: C<A> = A, no S, C dense
425         //  M   -   x   -   A   -       25:  C<M,s> = A, A dense, C empty
426         //  M   -   -   -   A   -       06n: C(I,J)<M> = A, no S
427         //  M   -   -   -   A   S       06s: C(I,J)<M> = A, with S
428 
429         ASSERT (!scalar_expansion) ;        // A is a matrix
430         ASSERT (M != NULL && !Mask_comp) ;  // mask M present, not compl.
431         ASSERT (!C_replace) ;
432 
433         if (accum != NULL)
434         {
435             if (S_Extraction)
436             {
437                 // Method 08s: C(I,J)<M> += A ; with S
438                 subassign_method = GB_SUBASSIGN_METHOD_08s ;
439             }
440             else
441             {
442                 // Method 08n: C(I,J)<M> += A ; no S
443                 // No matrix can be bitmap.
444                 subassign_method = GB_SUBASSIGN_METHOD_08n ;
445             }
446         }
447         else if (method_06d)
448         {
449             // Method 06d: C(:,:)<A> = A ; no S, C dense or full;
450             subassign_method = GB_SUBASSIGN_METHOD_06d ;
451             ASSERT ((C_as_if_full || C_is_bitmap) && whole_C_matrix && M == A) ;
452             ASSERT ((C_as_if_full || C_is_bitmap) && whole_C_matrix && M == A) ;
453         }
454         else if (method_25)
455         {
456             // Method 25: C<M,struct> = A, C empty; A is dense, full, or bitmap
457             subassign_method = GB_SUBASSIGN_METHOD_25 ;
458         }
459         else if (!S_Extraction)
460         {
461             // Method 06n: C(I,J)<M> = A ; no S
462             // If M or A are bitmap, this method is not used;
463             // 06s is used instead.
464             subassign_method = GB_SUBASSIGN_METHOD_06n ;
465         }
466         else
467         {
468             // Method 06s: C(I,J)<M> = A ; using S
469             subassign_method = GB_SUBASSIGN_METHOD_06s ;
470         }
471 
472     }
473     else if (M == NULL)
474     {
475 
476         //----------------------------------------------------------------------
477         // assignment using S_Extraction method, no mask M
478         //----------------------------------------------------------------------
479 
480         //  =====================       ==============
481         //  M   cmp rpl acc A   S       method: action
482         //  =====================       ==============
483         //  -   -   -   -   -   S       01:  C(I,J) = x, with S
484         //  -   -   -   -   A   S       02:  C(I,J) = A, with S
485         //  -   -   -   +   -   S       03:  C(I,J) += x, with S
486         //  -   -   -   +   A   S       04:  C(I,J) += A, with S
487 
488         ASSERT (!Mask_comp) ;
489         ASSERT (!C_replace) ;
490         ASSERT (S_Extraction) ;            // S is used
491 
492         if (scalar_expansion)
493         {
494             if (accum == NULL)
495             {
496                 // Method 01: C(I,J) = scalar ; using S
497                 subassign_method = GB_SUBASSIGN_METHOD_01 ;
498             }
499             else
500             {
501                 // Method 03: C(I,J) += scalar ; using S
502                 subassign_method = GB_SUBASSIGN_METHOD_03 ;
503             }
504         }
505         else
506         {
507             if (accum == NULL)
508             {
509                 // Method 02: C(I,J) = A ; using S
510                 subassign_method = GB_SUBASSIGN_METHOD_02 ;
511             }
512             else
513             {
514                 // Method 04: C(I,J) += A ; using S
515                 subassign_method = GB_SUBASSIGN_METHOD_04 ;
516             }
517         }
518 
519     }
520     else if (scalar_expansion)
521     {
522 
523         //----------------------------------------------------------------------
524         // C(I,J)<#M> = scalar or += scalar ; using S
525         //----------------------------------------------------------------------
526 
527         //  =====================       ==============
528         //  M   cmp rpl acc A   S       method: action
529         //  =====================       ==============
530         //  M   -   r   -   -   S       09:  C(I,J)<M,repl> = x, with S
531         //  M   -   r   +   -   S       11:  C(I,J)<M,repl> += x, with S
532         //  M   c   -   -   -   S       13:  C(I,J)<!M> = x, with S
533         //  M   c   -   +   -   S       15:  C(I,J)<!M> += x, with S
534         //  M   c   r   -   -   S       17:  C(I,J)<!M,repl> = x, with S
535         //  M   c   r   +   -   S       19:  C(I,J)<!M,repl> += x, with S
536 
537         ASSERT (!C_Mask_scalar) ;
538         ASSERT (C_replace || Mask_comp) ;
539         ASSERT (S_Extraction) ;            // S is used
540 
541         if (accum == NULL)
542         {
543             if (Mask_comp && C_replace)
544             {
545                 // Method 17: C(I,J)<!M,repl> = scalar ; using S
546                 subassign_method = GB_SUBASSIGN_METHOD_17 ;
547             }
548             else if (Mask_comp)
549             {
550                 // Method 13: C(I,J)<!M> = scalar ; using S
551                 subassign_method = GB_SUBASSIGN_METHOD_13 ;
552             }
553             else // if (C_replace)
554             {
555                 // Method 09: C(I,J)<M,repl> = scalar ; using S
556                 ASSERT (C_replace) ;
557                 subassign_method = GB_SUBASSIGN_METHOD_09 ;
558             }
559         }
560         else
561         {
562             if (Mask_comp && C_replace)
563             {
564                 // Method 19: C(I,J)<!M,repl> += scalar ; using S
565                 subassign_method = GB_SUBASSIGN_METHOD_19 ;
566             }
567             else if (Mask_comp)
568             {
569                 // Method 15: C(I,J)<!M> += scalar ; using S
570                 subassign_method = GB_SUBASSIGN_METHOD_15 ;
571             }
572             else // if (C_replace)
573             {
574                 // Method 11: C(I,J)<M,repl> += scalar ; using S
575                 ASSERT (C_replace) ;
576                 subassign_method = GB_SUBASSIGN_METHOD_11 ;
577             }
578         }
579 
580     }
581     else
582     {
583 
584         //------------------------------------------------------------------
585         // C(I,J)<#M> = A or += A ; using S
586         //------------------------------------------------------------------
587 
588         //  =====================       ==============
589         //  M   cmp rpl acc A   S       method: action
590         //  =====================       ==============
591         //  M   -   r   -   A   S       10:  C(I,J)<M,repl> = A, with S
592         //  M   -   r   +   A   S       12:  C(I,J)<M,repl> += A, with S
593         //  M   c   -   -   A   S       14:  C(I,J)<!M> = A, with S
594         //  M   c   -   +   A   S       16:  C(I,J)<!M> += A, with S
595         //  M   c   r   -   A   S       18:  C(I,J)<!M,repl> = A, with S
596         //  M   c   r   +   A   S       20:  C(I,J)<!M,repl> += A, with S
597 
598         ASSERT (Mask_comp || C_replace) ;
599         ASSERT (S_Extraction) ;            // S is used
600 
601         if (accum == NULL)
602         {
603             if (Mask_comp && C_replace)
604             {
605                 // Method 18: C(I,J)<!M,repl> = A ; using S
606                 subassign_method = GB_SUBASSIGN_METHOD_18 ;
607             }
608             else if (Mask_comp)
609             {
610                 // Method 14: C(I,J)<!M> = A ; using S
611                 subassign_method = GB_SUBASSIGN_METHOD_14 ;
612             }
613             else // if (C_replace)
614             {
615                 // Method 10: C(I,J)<M,repl> = A ; using S
616                 ASSERT (C_replace) ;
617                 subassign_method = GB_SUBASSIGN_METHOD_10 ;
618             }
619         }
620         else
621         {
622             if (Mask_comp && C_replace)
623             {
624                 // Method 20: C(I,J)<!M,repl> += A ; using S
625                 subassign_method = GB_SUBASSIGN_METHOD_20 ;
626             }
627             else if (Mask_comp)
628             {
629                 subassign_method = GB_SUBASSIGN_METHOD_16 ;
630             }
631             else // if (C_replace)
632             {
633                 // Method 12: C(I,J)<M,repl> += A ; using S
634                 ASSERT (C_replace) ;
635                 subassign_method = GB_SUBASSIGN_METHOD_12 ;
636             }
637         }
638     }
639 
640     //--------------------------------------------------------------------------
641     // determine if the subassign method can handle this case for bitmaps
642     //--------------------------------------------------------------------------
643 
644     bool C_is_full = GB_IS_FULL (C) ;
645 
646     #define GB_USE_BITMAP_IF(condition) \
647         if (condition) subassign_method = GB_SUBASSIGN_METHOD_BITMAP ;
648 
649     switch (subassign_method)
650     {
651 
652         //----------------------------------------------------------------------
653         // scalar assignent methods
654         //----------------------------------------------------------------------
655 
656         case GB_SUBASSIGN_METHOD_01 :   // C(I,J) = scalar
657         case GB_SUBASSIGN_METHOD_03 :   // C(I,J) += scalar
658         case GB_SUBASSIGN_METHOD_05 :   // C(I,J)<M> = scalar
659         case GB_SUBASSIGN_METHOD_07 :   // C(I,J)<M> += scalar
660         case GB_SUBASSIGN_METHOD_13 :   // C(I,J)<!M> = scalar
661         case GB_SUBASSIGN_METHOD_15 :   // C(I,J)<!M> += scalar
662         case GB_SUBASSIGN_METHOD_21 :   // C(:,:) = scalar
663             // M can have any sparsity structure, including bitmap
664             GB_USE_BITMAP_IF (C_is_bitmap) ;
665             break ;
666 
667         case GB_SUBASSIGN_METHOD_05d :  // C(:,:)<M> = scalar ; C is dense
668         case GB_SUBASSIGN_METHOD_05e :  // C(:,:)<M,struct> = scalar ; C empty
669         case GB_SUBASSIGN_METHOD_05f :  // C(:,:)<C,struct> = scalar
670         case GB_SUBASSIGN_METHOD_22 :   // C += scalar ; C is dense
671             // C and M can have any sparsity pattern, including bitmap
672             break ;
673 
674         case GB_SUBASSIGN_METHOD_09 :   // C(I,J)<M,replace> = scalar
675         case GB_SUBASSIGN_METHOD_11 :   // C(I,J)<M,replace> += scalar
676         case GB_SUBASSIGN_METHOD_17 :   // C(I,J)<!M,replace> = scalar
677         case GB_SUBASSIGN_METHOD_19 :   // C(I,J)<!M,replace> = scalar
678             // M can have any sparsity structure, including bitmap
679             GB_USE_BITMAP_IF (C_is_bitmap || C_is_full) ;
680             break ;
681 
682         //----------------------------------------------------------------------
683         // matrix assignent methods
684         //----------------------------------------------------------------------
685 
686         // GB_accum_mask may use any of these methods, with I and J as GB_ALL.
687 
688         case GB_SUBASSIGN_METHOD_02 :   // C(I,J) = A
689         case GB_SUBASSIGN_METHOD_06s :  // C(I,J)< M> = A ; with S
690         case GB_SUBASSIGN_METHOD_14 :   // C(I,J)<!M> = A
691         case GB_SUBASSIGN_METHOD_10 :   // C(I,J)< M,replace> = A
692         case GB_SUBASSIGN_METHOD_18 :   // C(I,J)<!M,replace> = A
693         case GB_SUBASSIGN_METHOD_12 :   // C(I,J)< M,replace> += A
694         case GB_SUBASSIGN_METHOD_20 :   // C(I,J)<!M,replace> += A
695             // M can have any sparsity structure, including bitmap
696             GB_USE_BITMAP_IF (C_is_bitmap || C_is_full) ;
697             break ;
698 
699         case GB_SUBASSIGN_METHOD_04 :   // C(I,J) += A
700         case GB_SUBASSIGN_METHOD_08s :  // C(I,J)< M> += A, with S
701         case GB_SUBASSIGN_METHOD_16 :   // C(I,J)<!M> += A
702         case GB_SUBASSIGN_METHOD_24 :   // C = A
703             // M can have any sparsity structure, including bitmap
704             GB_USE_BITMAP_IF (C_is_bitmap) ;
705             break ;
706 
707         case GB_SUBASSIGN_METHOD_06d :  // C(:,:)<A> = A ; C is dense
708         case GB_SUBASSIGN_METHOD_23 :   // C += A ; C is dense
709             // C, M, and A can have any sparsity structure, including bitmap
710             break ;
711 
712         case GB_SUBASSIGN_METHOD_25 :   // C(:,:)<M,struct> = A ; C empty
713             // C, M, and A can have any sparsity structure, including bitmap,
714             // but if M is bitmap or full, use bitmap assignment instead.
715             GB_USE_BITMAP_IF (M_is_bitmap || GB_IS_FULL (M)) ;
716             break ;
717 
718         case GB_SUBASSIGN_METHOD_06n :  // C(I,J)<M> = A ; no S
719             // If M or A are bitmap, Method 06s is used instead of 06n.
720             GB_USE_BITMAP_IF (C_is_bitmap || C_is_full) ;
721             ASSERT (!M_is_bitmap) ;
722             ASSERT (!A_is_bitmap) ;
723             break ;
724 
725         case GB_SUBASSIGN_METHOD_08n :  // C(I,J)<M> += A, no S
726             // Method 08s is used instead of 08n if M or A are bitmap.
727             GB_USE_BITMAP_IF (C_is_bitmap) ;
728             ASSERT (!M_is_bitmap) ;
729             ASSERT (!A_is_bitmap) ;
730             break ;
731 
732         // case GB_SUBASSIGN_METHOD_BITMAP:
733         default :;
734             subassign_method = GB_SUBASSIGN_METHOD_BITMAP ;
735     }
736 
737     //--------------------------------------------------------------------------
738     // return result
739     //--------------------------------------------------------------------------
740 
741     return (subassign_method) ;
742 }
743 
744