//------------------------------------------------------------------------------
// GB_ek_slice.h: slice the entries and vectors of a matrix
//------------------------------------------------------------------------------

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

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

#ifndef GB_EK_SLICE_H
#define GB_EK_SLICE_H

#include "GB.h"

//------------------------------------------------------------------------------
// GB_ek_slice prototypes
//------------------------------------------------------------------------------

// Slice the entries of a matrix or vector into ntasks slices.

// Task t does entries pstart_slice [t] to pstart_slice [t+1]-1 and
// vectors kfirst_slice [t] to klast_slice [t].  The first and last vectors
// may be shared with prior slices and subsequent slices.

// On input, ntasks must be <= nnz (A), unless nnz (A) is zero.  In that
// case, ntasks must be 1.

// See GB_callbacks.h:
// GB_CALLBACK_EK_SLICE_PROTO (GB_ek_slice) ;
// GB_CALLBACK_EK_SLICE_MERGE1_PROTO (GB_ek_slice_merge1) ;

void GB_ek_slice_merge2     // merge final results for matrix C
(
    // output
    int64_t *C_nvec_nonempty,       // # of non-empty vectors in C
    int64_t *restrict Cp_kfirst,    // size ntasks
    // input/output
    int64_t *restrict Cp,           // size cnvec+1
    // input
    const int64_t cnvec,
    const int64_t *restrict Wfirst, // size ntasks
    const int64_t *restrict Wlast,  // size ntasks
    const int64_t *A_ek_slicing,    // size 3*ntasks+1
    const int ntasks,               // # of tasks used to construct C
    const int nthreads,             // # of threads to use
    GB_Werk Werk
) ;

//------------------------------------------------------------------------------
// GB_get_pA_and_pC: find the part of A(:,k) and C(:,k) for this task
//------------------------------------------------------------------------------

// The tasks were generated by GB_ek_slice.

// GB_get_pA_and_pC is no longer used.  JIT kernels and templates use
// use the GB_GET_PA_AND_PC macro instead, #define'd in
// Source/slice/include/GB_ek_slice_kernels.h.

// FIXME: replace GB_GET_PA_AND_PC with this static inline function and use
// this instead (but without the assignment of p0 and p1).

#if 0
static inline void GB_get_pA_and_pC
(
    // output
    int64_t *pA_start,
    int64_t *pA_end,
    int64_t *pC,
    // input
    int tid,            // task id
    int64_t k,          // current vector
    int64_t kfirst,     // first vector for this slice
    int64_t klast,      // last vector for this slice
    const int64_t *restrict pstart_slice,   // start of each slice in A
    const int64_t *restrict Cp_kfirst,      // start of each slice in C
    const int64_t *restrict Cp,             // vector pointers for C
    int64_t cvlen,                             // C->vlen
    const int64_t *restrict Ap,             // vector pointers for A
    int64_t avlen                              // A->vlen
)
{

    // get the start of vector k and k+1 (does not appear in GB_GET_PA_AND_PC)
    int64_t p0 = GBP (Ap, k, avlen) ;
    int64_t p1 = GBP (Ap, k+1, avlen) ;

    if (k == kfirst)
    {
        // First vector for task tid; may only be partially owned.
        (*pA_start) = pstart_slice [tid] ;
        (*pA_end  ) = GB_IMIN (p1, pstart_slice [tid+1]) ;
        (*pC) = Cp_kfirst [tid] ;
    }
    else if (k == klast)
    {
        // Last vector for task tid; may only be partially owned.
        (*pA_start) = p0 ;
        (*pA_end  ) = pstart_slice [tid+1] ;
        (*pC) = GBP (Cp, k, cvlen) ;
    }
    else
    {
        // task tid entirely owns this vector A(:,k).
        (*pA_start) = p0 ;
        (*pA_end  ) = p1 ;
        (*pC) = GBP (Cp, k, cvlen) ;
    }
}
#endif

//------------------------------------------------------------------------------
// GB_get_pA: find the part of A(:,k) to be operated on by this task
//------------------------------------------------------------------------------

// The tasks were generated by GB_ek_slice.

// GB_get_pA is only used for non-templatized factory methods, not in any JIT
// kernels or templates.  JIT kernels and templates use the GB_GET_PA macro
// instead, #define'd in Source/slice/include/GB_ek_slice_kernels.h.

// GB_get_pA and GB_GET_PA are very similar, except that GB_get_pA computes
// p0 and p1.

// FIXME: unify GB_get_pA and GB_GET_PA into a single method.

static inline void GB_get_pA
(
    // output
    int64_t *pA_start,
    int64_t *pA_end,
    // input
    int tid,            // task id
    int64_t k,          // current vector
    int64_t kfirst,     // first vector for this slice
    int64_t klast,      // last vector for this slice
    const int64_t *restrict pstart_slice,   // start of each slice in A
    const int64_t *restrict Ap,             // vector pointers for A
    int64_t avlen                              // A->vlen
)
{

    // get the start of vector k and k+1 (does not appear in GB_GET_PA)
    int64_t p0 = GBP (Ap, k, avlen) ;
    int64_t p1 = GBP (Ap, k+1, avlen) ;

    if (k == kfirst)
    { 
        // First vector for task tid; may only be partially owned.
        (*pA_start) = pstart_slice [tid] ;
        (*pA_end  ) = GB_IMIN (p1, pstart_slice [tid+1]) ;
    }
    else if (k == klast)
    { 
        // Last vector for task tid; may only be partially owned.
        (*pA_start) = p0 ;
        (*pA_end  ) = pstart_slice [tid+1] ;
    }
    else
    { 
        // task tid entirely owns this vector A(:,k).
        (*pA_start) = p0 ;
        (*pA_end  ) = p1 ;
    }
}

#endif

