Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dealing with all of the variants of apply #3

Open
mcmillan03 opened this issue Oct 12, 2021 · 1 comment
Open

Dealing with all of the variants of apply #3

mcmillan03 opened this issue Oct 12, 2021 · 1 comment

Comments

@mcmillan03
Copy link
Member

mcmillan03 commented Oct 12, 2021

The GraphBLAS C API v. 2.0 has the following variants and signatures (pseudocode)

Standard Variants

  • standard vector variant: apply(Vec w, Vec mask, BinaryOp accum, UnaryOp op, Vec U, ...)
  • standard matrix variant: apply(Mat C, Mat Mask, BinaryOp accum, UnaryOp op, Mat A, ...)

BinaryOp bind 1st/2nd Variants

  • bind-1st vector variant: apply(Vec w, Vec mask, BinaryOp accum, BinaryOp op, Scalar s, Vec U, ...)
  • bind-2nd vector variant: apply(Vec w, Vec mask, BinaryOp accum, BinaryOp op, Vec U, Scalar s, ...)
  • standard matrix variant: apply(Mat C, Mat Mask, BinaryOp accum, BinaryOp op, Scalar s, Mat A, ...)
  • standard matrix variant: apply(Mat C, Mat Mask, BinaryOp accum, BinaryOp op, Mat A, Scalar s, ...)

IndexUnaryOp Variants

  • standard vector variant: apply(Vec w, Vec mask, BinaryOp accum, IndexUnaryOp op, Vec U, Scalar s, ...)
  • standard matrix variant: apply(Mat C, Mat Mask, BinaryOp accum, IndexUnaryOp op, Mat A, Scalar s, ...)

The C++ API way of defining the standard vector signature is as follows (matrix follows the same pattern):

    template<typename T, typename I, typename Hint, typename Allocator,
             typename MaskType,
             typename AccumulatorType,
             typename UnaryOpType,
             typename UVectorType>
    void apply(vector<T, I, Hint, Allocator>  &w,
               MaskType                 const &mask,
               AccumulatorType                 accum,
               UnaryOpType                     op,
               UVectorType              const &u,
               OutputControlEnum               outp = MERGE);

The one might define the BinaryOp+bind as follows but bind-1st and bind-second have the same templated signature and need to be dealt with with a static assert in the body as follows:

    template<typename T, typename I, typename Hint, typename Allocator,
             typename MaskT,
             typename AccumT,
             typename BinaryOpT,
             typename FirstT,
             typename SecondT>
    inline void apply(
        vector<T, I, Hint, Allocator>  &w,
        MaskT                    const &mask,
        AccumT                          accum,
        BinaryOpT                       op,
        FirstT                   const &lhs,
        SecondT                  const &rhs,
        OutputControlEnum               outp = MERGE)
    {
        // figure out if the user wants bind1st or bind2nd based on the arg types
        constexpr bool is_bind1st = is_vector_v<SecondT>;
        constexpr bool is_bind2nd = is_vector_v<FirstT>;

        // make sure only one of the types matches
        static_assert(is_bind1st ^ is_bind2nd, "apply isn't going to work");
        ...
    }

However this signature is not recommended for the C++ API was we should be using std::bind at the call site and call the standard variant as follows (for bind-2nd):

        // multiply all elements of m by damping_factor
        grb::apply(m, grb::NoMask(), grb::NoAccumulate(),
                   std::bind(grb::Times<RealT>(),
                             std::placeholders::_1,
                             damping_factor),
                   m);

Without the BinaryOp-bind variants then there is no collision with what the IndexUnaryOp variant would be, but one may still want to asser that u is a vector:

    template<typename T, typename I, typename Hint, typename Allocator,
             typename MaskType,
             typename AccumulatorType,
             typename IndexUnaryOpType,
             typename UVectorType>
    void apply(vector<T, I, Hint, Allocator>  &w,
               MaskType                 const &mask,
               AccumulatorType                 accum,
               IndexUnaryOpType                op,
               ValueType                const &s
               UVectorType              const &u,
               OutputControlEnum               outp = MERGE);

Is this approach the best? I see no way to do binding for index unary ops and call the standard variant because. While I could find a way to bind the val parameter, the element location indices need to be provided at the call site inside the implementation of apply.

@BenBrock
Copy link
Collaborator

BenBrock commented Sep 9, 2022

Most of the variants of extract and apply are handled by some combination of:

  1. submatrix_view, and then copying or assigning the submatrix
  2. mask_view
  3. grb::assign

We should take a deeper look as we go through algorithms over the next few weeks and see if we need to expand these features or add new ones to handle all of the C API's extract/assign.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants