1 //------------------------------------------------------------------------------
2 // GB_emult_01_phase1: # entries in C=A.*B or C<M or !M>=A.*B (C sparse/hyper)
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 // GB_emult_01_phase1 counts the number of entries in each vector of C, for
11 // C=A.*B, C<M>=A.*B, or C<!M>=A.*B and then does a cumulative sum to find Cp.
12 // GB_emult_01_phase1 is preceded by GB_emult_01_phase0, which finds the
13 // non-empty vectors of C.  If the mask M is saprse, it is not complemented;
14 // only a bitmap or full M is complemented.
15 
16 // C is sparse or hypersparse, as determined by GB_add_sparsity.
17 // M, A, and B can have any sparsity structure, but only a specific set of
18 // cases will be used (see GB_emult_sparsity for details).
19 
20 // Cp is either freed by GB_emult_01_phase2, or transplanted into C.
21 
22 #include "GB_emult.h"
23 
GB_emult_01_phase1(int64_t ** Cp_handle,size_t * Cp_size_handle,int64_t * Cnvec_nonempty,GB_task_struct * restrict TaskList,const int C_ntasks,const int C_nthreads,const int64_t Cnvec,const int64_t * restrict Ch,const int64_t * restrict C_to_M,const int64_t * restrict C_to_A,const int64_t * restrict C_to_B,const GrB_Matrix M,const bool Mask_struct,const bool Mask_comp,const GrB_Matrix A,const GrB_Matrix B,GB_Context Context)24 GrB_Info GB_emult_01_phase1                 // count nnz in each C(:,j)
25 (
26     // computed by phase1:
27     int64_t **Cp_handle,                    // output of size Cnvec+1
28     size_t *Cp_size_handle,
29     int64_t *Cnvec_nonempty,                // # of non-empty vectors in C
30     // tasks from phase1a:
31     GB_task_struct *restrict TaskList,   // array of structs
32     const int C_ntasks,                     // # of tasks
33     const int C_nthreads,                   // # of threads to use
34     // analysis from phase0:
35     const int64_t Cnvec,
36     const int64_t *restrict Ch,          // Ch is NULL, or shallow pointer
37     const int64_t *restrict C_to_M,
38     const int64_t *restrict C_to_A,
39     const int64_t *restrict C_to_B,
40     // original input:
41     const GrB_Matrix M,             // optional mask, may be NULL
42     const bool Mask_struct,         // if true, use the only structure of M
43     const bool Mask_comp,           // if true, use !M
44     const GrB_Matrix A,
45     const GrB_Matrix B,
46     GB_Context Context
47 )
48 {
49 
50     //--------------------------------------------------------------------------
51     // check inputs
52     //--------------------------------------------------------------------------
53 
54     ASSERT (Cp_handle != NULL) ;
55     ASSERT (Cp_size_handle != NULL) ;
56     ASSERT (Cnvec_nonempty != NULL) ;
57 
58     ASSERT_MATRIX_OK_OR_NULL (M, "M for emult phase1", GB0) ;
59     ASSERT (!GB_ZOMBIES (M)) ;
60     ASSERT (!GB_JUMBLED (M)) ;
61     ASSERT (!GB_PENDING (M)) ;
62 
63     ASSERT_MATRIX_OK (A, "A for emult phase1", GB0) ;
64     ASSERT (!GB_ZOMBIES (A)) ;
65     ASSERT (!GB_JUMBLED (A)) ;
66     ASSERT (!GB_PENDING (A)) ;
67 
68     ASSERT_MATRIX_OK (B, "B for emult phase1", GB0) ;
69     ASSERT (!GB_ZOMBIES (B)) ;
70     ASSERT (!GB_JUMBLED (B)) ;
71     ASSERT (!GB_PENDING (B)) ;
72 
73     ASSERT (A->vdim == B->vdim) ;
74 
75     if (M == NULL)
76     {
77         ASSERT (GB_IS_SPARSE (A) || GB_IS_HYPERSPARSE (A)) ;
78         ASSERT (GB_IS_SPARSE (B) || GB_IS_HYPERSPARSE (B)) ;
79     }
80 
81     //--------------------------------------------------------------------------
82     // allocate the result
83     //--------------------------------------------------------------------------
84 
85     (*Cp_handle) = NULL ;
86     int64_t *restrict Cp = NULL ; size_t Cp_size = 0 ;
87     Cp = GB_CALLOC (GB_IMAX (2, Cnvec+1), int64_t, &Cp_size) ;
88     if (Cp == NULL)
89     {
90         // out of memory
91         return (GrB_OUT_OF_MEMORY) ;
92     }
93 
94     //--------------------------------------------------------------------------
95     // count the entries in each vector of C
96     //--------------------------------------------------------------------------
97 
98     #define GB_PHASE_1_OF_2
99     #include "GB_emult_01_meta.c"
100 
101     //--------------------------------------------------------------------------
102     // cumulative sum of Cp and fine tasks in TaskList
103     //--------------------------------------------------------------------------
104 
105     GB_task_cumsum (Cp, Cnvec, Cnvec_nonempty, TaskList, C_ntasks, C_nthreads,
106         Context) ;
107 
108     //--------------------------------------------------------------------------
109     // return the result
110     //--------------------------------------------------------------------------
111 
112     (*Cp_handle) = Cp ;
113     (*Cp_size_handle) = Cp_size ;
114     return (GrB_SUCCESS) ;
115 }
116 
117