File: GB_reduce_to_scalar_template.c

package info (click to toggle)
suitesparse 1%3A7.10.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, trixie
  • size: 254,920 kB
  • sloc: ansic: 1,134,743; cpp: 46,133; makefile: 4,875; fortran: 2,087; java: 1,826; sh: 996; ruby: 725; python: 495; asm: 371; sed: 166; awk: 44
file content (140 lines) | stat: -rw-r--r-- 4,774 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//------------------------------------------------------------------------------
// GB_reduce_to_scalar_template: z=reduce(A), reduce a matrix to a scalar
//------------------------------------------------------------------------------

// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2025, All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//------------------------------------------------------------------------------

// Reduce a matrix to a scalar, with typecasting and generic operators.
// No panel is used.  The workspace W always has the same type as the ztype
// of the monoid, GB_Z_TYPE.

// z += W [i], no typecast
#ifndef GB_ADD_ARRAY_TO_SCALAR
#define GB_ADD_ARRAY_TO_SCALAR(z,W,i) GB_UPDATE (z, W [i])
#endif

// W [k] = z, no typecast
#ifndef GB_COPY_SCALAR_TO_ARRAY
#define GB_COPY_SCALAR_TO_ARRAY(W,k,z) W [k] = z
#endif

{

    //--------------------------------------------------------------------------
    // get A
    //--------------------------------------------------------------------------

    GB_Ai_DECLARE (Ai, const) ; GB_Ai_PTR (Ai, A) ;

    const int8_t  *restrict Ab = A->b ;
    const GB_A_TYPE *restrict Ax = (GB_A_TYPE *) A->x ;
    GB_A_NHELD (anz) ;      // int64_t anz = GB_nnz_held (A) ;
    ASSERT (anz > 0) ;
    #ifdef GB_JIT_KERNEL
    #define A_has_zombies GB_A_HAS_ZOMBIES
    #else
    const bool A_has_zombies = (A->nzombies > 0) ;
    #endif
    ASSERT (!A->iso) ;
    #if GB_MONOID_IS_TERMINAL
    GB_DECLARE_TERMINAL_CONST (zterminal) ;
    #endif

    //--------------------------------------------------------------------------
    // reduce A to a scalar
    //--------------------------------------------------------------------------

    if (nthreads == 1)
    {

        //----------------------------------------------------------------------
        // single thread
        //----------------------------------------------------------------------

        for (int64_t p = 0 ; p < anz ; p++)
        { 
            // skip if the entry is a zombie or if not in the bitmap
            if (A_has_zombies)
            { 
                int64_t i = GB_IGET (Ai, p) ;
                if (GB_IS_ZOMBIE (i)) continue ;
            }
            if (!GBb_A (Ab, p)) continue ;
            // z += (ztype) Ax [p]
            GB_GETA_AND_UPDATE (z, Ax, p) ;
            #if GB_MONOID_IS_TERMINAL
            // check for early exit
            GB_IF_TERMINAL_BREAK (z, zterminal) ;
            #endif
        }

    }
    else
    {

        //----------------------------------------------------------------------
        // each thread reduces its own slice in parallel
        //----------------------------------------------------------------------

        bool early_exit = false ;
        int tid ;

        #pragma omp parallel for num_threads(nthreads) schedule(dynamic,1)
        for (tid = 0 ; tid < ntasks ; tid++)
        {
            int64_t pstart, pend ;
            GB_PARTITION (pstart, pend, anz, tid, ntasks) ;
            // ztype t = identity
            GB_DECLARE_IDENTITY (t) ;
            bool my_exit, found = false ;
            GB_ATOMIC_READ
            my_exit = early_exit ;
            if (!my_exit)
            {
                for (int64_t p = pstart ; p < pend ; p++)
                { 
                    // skip if the entry is a zombie or if not in the bitmap
                    if (A_has_zombies)
                    { 
                        int64_t i = GB_IGET (Ai, p) ;
                        if (GB_IS_ZOMBIE (i)) continue ;
                    }
                    if (!GBb_A (Ab, p)) continue ;
                    found = true ;
                    // t += (ztype) Ax [p]
                    GB_GETA_AND_UPDATE (t, Ax, p) ;
                    #if GB_MONOID_IS_TERMINAL
                    // check for early exit
                    if (GB_TERMINAL_CONDITION (t, zterminal))
                    { 
                        // tell the other tasks to exit early
                        GB_ATOMIC_WRITE
                        early_exit = true ;
                        break ;
                    }
                    #endif
                }
            }
            F [tid] = found ;
            // W [tid] = t, no typecast
            GB_COPY_SCALAR_TO_ARRAY (W, tid, t) ;
        }

        //----------------------------------------------------------------------
        // sum up the results of each slice using a single thread
        //----------------------------------------------------------------------

        for (int tid = 0 ; tid < ntasks ; tid++)
        {
            if (F [tid])
            { 
                // z += W [tid], no typecast
                GB_ADD_ARRAY_TO_SCALAR (z, W, tid) ;
            }
        }
    }
}