1 //------------------------------------------------------------------------------
2 // GB_reduce_to_scalar_template: s=reduce(A), reduce a matrix to 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 // Reduce a matrix to a scalar, with typecasting and generic operators.
11 // No panel is used.
12 
13 {
14 
15     //--------------------------------------------------------------------------
16     // get A
17     //--------------------------------------------------------------------------
18 
19     const int8_t   *restrict Ab = A->b ;
20     const int64_t  *restrict Ai = A->i ;
21     const GB_ATYPE *restrict Ax = (GB_ATYPE *) A->x ;
22     int64_t anz = GB_NNZ_HELD (A) ;
23     ASSERT (anz > 0) ;
24     const bool A_has_zombies = (A->nzombies > 0) ;
25 
26     //--------------------------------------------------------------------------
27     // reduce A to a scalar
28     //--------------------------------------------------------------------------
29 
30     if (nthreads == 1)
31     {
32 
33         //----------------------------------------------------------------------
34         // single thread
35         //----------------------------------------------------------------------
36 
37         for (int64_t p = 0 ; p < anz ; p++)
38         {
39             // skip if the entry is a zombie or if not in the bitmap
40             if (A_has_zombies && GB_IS_ZOMBIE (Ai [p])) continue ;
41             if (!GBB (Ab, p)) continue ;
42             // s = op (s, (ztype) Ax [p])
43             GB_ADD_CAST_ARRAY_TO_SCALAR (s, Ax, p) ;
44             // check for early exit
45             #if GB_HAS_TERMINAL
46             if (GB_IS_TERMINAL (s)) break ;
47             #endif
48         }
49 
50     }
51     else
52     {
53 
54         //----------------------------------------------------------------------
55         // each thread reduces its own slice in parallel
56         //----------------------------------------------------------------------
57 
58         bool early_exit = false ;
59         int tid ;
60 
61         #pragma omp parallel for num_threads(nthreads) schedule(dynamic,1)
62         for (tid = 0 ; tid < ntasks ; tid++)
63         {
64             int64_t pstart, pend ;
65             GB_PARTITION (pstart, pend, anz, tid, ntasks) ;
66             // ztype t = identity
67             GB_SCALAR_IDENTITY (t) ;
68             bool my_exit, found = false ;
69             GB_ATOMIC_READ
70             my_exit = early_exit ;
71             if (!my_exit)
72             {
73                 for (int64_t p = pstart ; p < pend ; p++)
74                 {
75                     // skip if the entry is a zombie or if not in the bitmap
76                     if (A_has_zombies && GB_IS_ZOMBIE (Ai [p])) continue ;
77                     if (!GBB (Ab, p)) continue ;
78                     found = true ;
79                     // t = op (t, (ztype) Ax [p]), with typecast
80                     GB_ADD_CAST_ARRAY_TO_SCALAR (t, Ax, p) ;
81                     // check for early exit
82                     #if GB_HAS_TERMINAL
83                     if (GB_IS_TERMINAL (t))
84                     {
85                         // tell the other tasks to exit early
86                         GB_ATOMIC_WRITE
87                         early_exit = true ;
88                         break ;
89                     }
90                     #endif
91                 }
92             }
93             F [tid] = found ;
94             // W [tid] = t, no typecast
95             GB_COPY_SCALAR_TO_ARRAY (W, tid, t) ;
96         }
97 
98         //----------------------------------------------------------------------
99         // sum up the results of each slice using a single thread
100         //----------------------------------------------------------------------
101 
102         for (int tid = 0 ; tid < ntasks ; tid++)
103         {
104             if (F [tid])
105             {
106                 // s = op (s, W [tid]), no typecast
107                 GB_ADD_ARRAY_TO_SCALAR (s, W, tid) ;
108             }
109         }
110     }
111 }
112 
113