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