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 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
//------------------------------------------------------------------------------
// GB_subref_phase3: C=A(I,J)
//------------------------------------------------------------------------------
// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//------------------------------------------------------------------------------
// This function either frees Cp and Ch, or transplants then into C, as C->p
// and C->h. Either way, the caller must not free them.
#include "GB_subref.h"
#include "GB_sort.h"
#include "GB_unused.h"
GrB_Info GB_subref_phase3 // C=A(I,J)
(
GrB_Matrix C, // output matrix, static header
// from phase2:
int64_t **Cp_handle, // vector pointers for C
size_t Cp_size,
const int64_t Cnvec_nonempty, // # of non-empty vectors in C
// from phase1:
const GB_task_struct *restrict TaskList, // array of structs
const int ntasks, // # of tasks
const int nthreads, // # of threads to use
const bool post_sort, // true if post-sort needed
const int64_t *Mark, // for I inverse buckets, size A->vlen
const int64_t *Inext, // for I inverse buckets, size nI
const int64_t nduplicates, // # of duplicates, if I inverted
// from phase0:
int64_t **Ch_handle,
size_t Ch_size,
const int64_t *restrict Ap_start,
const int64_t *restrict Ap_end,
const int64_t Cnvec,
const bool need_qsort,
const int Ikind,
const int64_t nI,
const int64_t Icolon [3],
const int64_t nJ,
// from GB_subref:
const bool C_iso, // if true, C is iso
const GB_void *cscalar, // iso value of C
// original input:
const bool C_is_csc, // format of output matrix C
const GrB_Matrix A,
const GrB_Index *I,
const bool symbolic,
GB_Context Context
)
{
//--------------------------------------------------------------------------
// check inputs
//--------------------------------------------------------------------------
ASSERT (C != NULL && (C->static_header || GBNSTATIC)) ;
ASSERT (Cp_handle != NULL) ;
ASSERT (Ch_handle != NULL) ;
const int64_t *restrict Ch = (*Ch_handle) ;
const int64_t *restrict Cp = (*Cp_handle) ;
ASSERT (Cp != NULL) ;
ASSERT_MATRIX_OK (A, "A for subref phase3", GB0) ;
ASSERT (!GB_IS_BITMAP (A)) ; // GB_bitmap_subref is used instead
//--------------------------------------------------------------------------
// allocate the output matrix C
//--------------------------------------------------------------------------
int64_t cnz = Cp [Cnvec] ;
bool C_is_hyper = (Ch != NULL) ;
GrB_Type ctype = (symbolic) ? GrB_INT64 : A->type ;
// allocate the result C (but do not allocate C->p or C->h)
int sparsity = C_is_hyper ? GxB_HYPERSPARSE : GxB_SPARSE ;
// set C->iso = C_iso OK
GrB_Info info = GB_new_bix (&C, // sparse or hyper, existing header
ctype, nI, nJ, GB_Ap_null, C_is_csc,
sparsity, true, A->hyper_switch, Cnvec, cnz, true, C_iso, Context) ;
if (info != GrB_SUCCESS)
{
// out of memory
GB_FREE (Cp_handle, Cp_size) ;
GB_FREE (Ch_handle, Ch_size) ;
return (info) ;
}
// add Cp as the vector pointers for C, from GB_subref_phase1
C->p = (int64_t *) Cp ; C->p_size = Cp_size ;
(*Cp_handle) = NULL ;
// add Ch as the hypersparse list for C, from GB_subref_phase0
if (C_is_hyper)
{
// transplant Ch into C
C->h = (int64_t *) Ch ; C->h_size = Ch_size ;
(*Ch_handle) = NULL ;
C->nvec = Cnvec ;
}
// now Cp and Ch have been transplanted into C, so they must not be freed.
ASSERT ((*Cp_handle) == NULL) ;
ASSERT ((*Ch_handle) == NULL) ;
C->nvec_nonempty = Cnvec_nonempty ;
C->nvals = cnz ;
C->magic = GB_MAGIC ;
//--------------------------------------------------------------------------
// phase3: C = A(I,J)
//--------------------------------------------------------------------------
#define GB_PHASE_2_OF_2
int64_t *restrict Ci = C->i ;
int64_t *restrict Cx = (int64_t *) C->x ;
if (symbolic)
{
//----------------------------------------------------------------------
// symbolic subref
//----------------------------------------------------------------------
ASSERT (!C_iso) ;
// symbolic subref must handle zombies
const int64_t nzombies = A->nzombies ;
// symbolic copy: Cx is int64_t; the values of A ignored
#define GB_COPY_RANGE(pC,pA,len) \
for (int64_t k = 0 ; k < (len) ; k++) \
{ \
Cx [(pC) + k] = (pA) + k ; \
}
#define GB_COPY_ENTRY(pC,pA) Cx [pC] = (pA) ;
#define GB_CSIZE1 1
#define GB_CSIZE2 (sizeof (int64_t))
#define GB_SYMBOLIC
#include "GB_subref_template.c"
}
else if (C_iso)
{
//----------------------------------------------------------------------
// iso numeric subref
//----------------------------------------------------------------------
// C is iso; no numeric values to extract; just set the iso value
memcpy (Cx, cscalar, A->type->size) ;
#define GB_COPY_RANGE(pC,pA,len) ;
#define GB_COPY_ENTRY(pC,pA) ;
#define GB_ISO_SUBREF
#include "GB_subref_template.c"
}
else
{
//----------------------------------------------------------------------
// non-iso numeric subref
//----------------------------------------------------------------------
// TODO: create versions for asize = 1, 2, 4, 8, 16, and other
ASSERT (C->type = A->type) ;
const int64_t asize = A->type->size ;
const GB_void *restrict Ax = (GB_void *) A->x ;
GB_void *restrict Cx = (GB_void *) C->x ;
// C and A have the same type
#define GB_COPY_RANGE(pC,pA,len) \
memcpy (Cx + (pC)*asize, Ax + (pA)*asize, (len) * asize) ;
#define GB_COPY_ENTRY(pC,pA) \
memcpy (Cx + (pC)*asize, Ax + (pA)*asize, asize) ;
#define GB_CSIZE1 asize
#define GB_CSIZE2 asize
#include "GB_subref_template.c"
}
//--------------------------------------------------------------------------
// remove empty vectors from C, if hypersparse
//--------------------------------------------------------------------------
info = GB_hypermatrix_prune (C, Context) ;
if (info != GrB_SUCCESS)
{
// out of memory
GB_phybix_free (C) ;
return (info) ;
}
//--------------------------------------------------------------------------
// return result
//--------------------------------------------------------------------------
// caller must not free Cp or Ch
ASSERT_MATRIX_OK (C, "C output for subref phase3", GB0) ;
return (GrB_SUCCESS) ;
}
|