ALP User Documentation  0.8.preview
Algebraic Programming User Documentation
blas0.hpp
Go to the documentation of this file.
1 
2 /*
3  * Copyright 2021 Huawei Technologies Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
27 #ifndef _H_GRB_BLAS0
28 #define _H_GRB_BLAS0
29 
30 #include <functional>
31 #include <stdexcept>
32 #include <type_traits> //enable_if
33 
35 #include "graphblas/rc.hpp"
37 
38 #define NO_CAST_ASSERT( x, y, z ) \
39  static_assert( x, \
40  "\n\n" \
41  "************************************************************************" \
42  "************************************************************************" \
43  "**********************\n" \
44  "* ERROR | " y " " z ".\n" \
45  "************************************************************************" \
46  "************************************************************************" \
47  "**********************\n" \
48  "* Possible fix 1 | Remove no_casting from the template parameters in " \
49  "this call to " y ".\n" \
50  "* Possible fix 2 | Provide a left-hand side input value of the same " \
51  "type as the first domain of the given operator.\n" \
52  "* Possible fix 3 | Provide a right-hand side input value of the same " \
53  "type as the second domain of the given operator.\n" \
54  "* Possible fix 4 | Provide an output value of the same type as the " \
55  "third domain of the given operator.\n" \
56  "* Note that in case of in-place operators the left-hand side input or " \
57  "right-hand side input also play the role of the output value.\n" \
58  "************************************************************************" \
59  "************************************************************************" \
60  "**********************\n" );
61 
62 
63 namespace grb {
64 
174  template<
176  class OP,
177  typename InputType1, typename InputType2, typename OutputType
178  >
179  static enum RC apply(
180  OutputType &out,
181  const InputType1 &x,
182  const InputType2 &y,
183  const OP &op = OP(),
184  const typename std::enable_if<
189  void >::type * = nullptr
190  ) {
191  // static sanity check
192  NO_CAST_ASSERT( ( !( descr & descriptors::no_casting ) || (
193  std::is_same< InputType1, typename OP::D1 >::value &&
194  std::is_same< InputType2, typename OP::D2 >::value &&
195  std::is_same< OutputType, typename OP::D3 >::value
196  ) ),
197  "grb::apply (BLAS level 0)",
198  "Argument value types do not match operator domains while no_casting "
199  "descriptor was set"
200  );
201 
202  // call apply
203  const typename OP::D1 left = static_cast< typename OP::D1 >( x );
204  const typename OP::D2 right = static_cast< typename OP::D2 >( y );
205  typename OP::D3 output = static_cast< typename OP::D3 >( out );
206  op.apply( left, right, output );
207  out = static_cast< OutputType >( output );
208 
209  // done
210  return SUCCESS;
211  }
212 
283  template<
285  class OP, typename InputType, typename IOType
286  >
287  static RC foldr(
288  const InputType &x,
289  IOType &y,
290  const OP &op = OP(),
291  const typename std::enable_if<
295  >::type * = nullptr
296  ) {
297  // static sanity check
298  NO_CAST_ASSERT( ( !(descr & descriptors::no_casting) || (
299  std::is_same< InputType, typename OP::D1 >::value &&
300  std::is_same< IOType, typename OP::D2 >::value &&
301  std::is_same< IOType, typename OP::D3 >::value
302  ) ), "grb::foldr (BLAS level 0)",
303  "Argument value types do not match operator domains while no_casting "
304  "descriptor was set" );
305 
306  // call foldr
307  const typename OP::D1 left = static_cast< typename OP::D1 >( x );
308  typename OP::D3 right = static_cast< typename OP::D3 >( y );
309  op.foldr( left, right );
310  y = static_cast< IOType >( right );
311 
312  // done
313  return SUCCESS;
314  }
315 
386  template<
388  class OP,
389  typename InputType, typename IOType
390  >
391  static RC foldl(
392  IOType &x,
393  const InputType &y,
394  const OP &op = OP(),
395  const typename std::enable_if< grb::is_operator< OP >::value &&
398  >::type * = nullptr
399  ) {
400  // static sanity check
401  NO_CAST_ASSERT( ( !(descr & descriptors::no_casting) || (
402  std::is_same< IOType, typename OP::D1 >::value &&
403  std::is_same< InputType, typename OP::D2 >::value &&
404  std::is_same< IOType, typename OP::D3 >::value
405  ) ), "grb::foldl (BLAS level 0)",
406  "Argument value types do not match operator domains while no_casting "
407  "descriptor was set" );
408 
409  // call foldl
410  typename OP::D1 left = static_cast< typename OP::D1 >( x );
411  const typename OP::D3 right = static_cast< typename OP::D3 >( y );
412  op.foldl( left, right );
413  x = static_cast< IOType >( left );
414 
415  // done
416  return SUCCESS;
417  }
418 
421  namespace internal {
422 
437  template<
438  grb::Descriptor descr,
439  typename OutputType, typename D,
440  typename Enabled = void
441  >
442  class ValueOrIndex;
443 
444  /* Version where use_index is allowed. */
445  template< grb::Descriptor descr, typename OutputType, typename D >
446  class ValueOrIndex<
447  descr,
448  OutputType, D,
449  typename std::enable_if<
450  std::is_arithmetic< OutputType >::value &&
451  !std::is_same< D, void >::value
452  >::type
453  > {
454 
455  private:
456 
457  static constexpr const bool use_index = descr & grb::descriptors::use_index;
458 
459  static_assert( use_index || std::is_convertible< D, OutputType >::value,
460  "Cannot convert to the requested output type" );
461 
462 
463  public:
464 
465  static OutputType getFromArray(
466  const D * __restrict__ const x,
467  const std::function< size_t( size_t ) > &src_local_to_global,
468  const size_t index
469  ) noexcept {
470  if( use_index ) {
471  return static_cast< OutputType >( src_local_to_global( index ) );
472  } else {
473  return static_cast< OutputType >( x[ index ] );
474  }
475  }
476 
477  static OutputType getFromScalar( const D &x, const size_t index ) noexcept {
478  if( use_index ) {
479  return static_cast< OutputType >( index );
480  } else {
481  return static_cast< OutputType >( x );
482  }
483  }
484 
485  };
486 
487  /* Version where use_index is not allowed. */
488  template< grb::Descriptor descr, typename OutputType, typename D >
489  class ValueOrIndex<
490  descr,
491  OutputType, D,
492  typename std::enable_if<
493  !std::is_arithmetic< OutputType >::value &&
494  !std::is_same< OutputType, void >::value
495  >::type
496  > {
497 
498  static_assert( !(descr & descriptors::use_index),
499  "use_index descriptor given while output type is not numeric" );
500 
501  static_assert( std::is_convertible< D, OutputType >::value,
502  "Cannot convert input to the given output type" );
503 
504  public:
505 
506  static OutputType getFromArray(
507  const D * __restrict__ const x,
508  const std::function< size_t( size_t ) > &,
509  const size_t index
510  ) noexcept {
511  return static_cast< OutputType >( x[ index ] );
512  }
513 
514  static OutputType getFromScalar(
515  const D &x, const size_t
516  ) noexcept {
517  return static_cast< OutputType >( x );
518  }
519 
520  };
521 
542  template<
543  bool identity_left,
544  typename OutputType, typename InputType,
545  template< typename > class Identity,
546  typename Enabled = void
547  >
548  class CopyOrApplyWithIdentity;
549 
550  /* The cast-and-assign version */
551  template<
552  bool identity_left,
553  typename OutputType, typename InputType,
554  template< typename > class Identity
555  >
556  class CopyOrApplyWithIdentity<
557  identity_left,
558  OutputType, InputType,
559  Identity,
560  typename std::enable_if<
561  std::is_convertible< InputType, OutputType >::value
562  >::type
563  > {
564 
565  public:
566 
567  template< typename Operator >
568  static void set( OutputType &out, const InputType &in, const Operator & ) {
569  out = static_cast< OutputType >( in );
570  }
571 
572  };
573 
574  /* The operator with identity version */
575  template<
576  bool identity_left,
577  typename OutputType, typename InputType,
578  template< typename > class Identity
579  >
580  class CopyOrApplyWithIdentity<
581  identity_left,
582  OutputType, InputType,
583  Identity,
584  typename std::enable_if<
585  !std::is_convertible< InputType, OutputType >::value
586  >::type
587  > {
588 
589  public:
590 
591  template< typename Operator >
592  static void set(
593  OutputType &out, const InputType &in, const Operator &op
594  ) {
595  const auto identity = identity_left ?
596  Identity< typename Operator::D1 >::value() :
597  Identity< typename Operator::D2 >::value();
598  if( identity_left ) {
599  (void) grb::apply( out, identity, in, op );
600  } else {
601  (void) grb::apply( out, in, identity, op );
602  }
603  }
604 
605  };
606 
607  } // namespace internal
608 
609 } // namespace grb
610 
611 #undef NO_CAST_ASSERT
612 
613 #endif // end ``_H_GRB_BLAS0''
614 
Defines the ALP error codes.
RC set(Vector< DataType, backend, Coords > &x, const T val, const Phase &phase=EXECUTE, const typename std::enable_if< !grb::is_object< DataType >::value &&!grb::is_object< T >::value, void >::type *const =nullptr) noexcept
Sets all elements of a vector to the given value.
Definition: io.hpp:858
RC
Return codes of ALP primitives.
Definition: rc.hpp:47
static constexpr Descriptor use_index
Instead of using input vector elements, use the index of those elements.
Definition: descriptors.hpp:167
static constexpr Descriptor no_casting
Disallows the standard casting of input parameters to a compatible domain in case they did not match ...
Definition: descriptors.hpp:196
Used to inspect whether a given type is an ALP/GraphBLAS object.
Definition: type_traits.hpp:130
static constexpr Descriptor no_operation
Indicates no additional pre- or post-processing on any of the GraphBLAS function arguments.
Definition: descriptors.hpp:63
unsigned int Descriptor
Descriptors indicate pre- or post-processing for some or all of the arguments to an ALP/GraphBLAS cal...
Definition: descriptors.hpp:54
static enum RC apply(OutputType &out, const InputType1 &x, const InputType2 &y, const OP &op=OP(), const typename std::enable_if< grb::is_operator< OP >::value &&!grb::is_object< InputType1 >::value &&!grb::is_object< InputType2 >::value &&!grb::is_object< OutputType >::value, void >::type *=nullptr)
Out-of-place application of the operator OP on two data elements.
Definition: blas0.hpp:179
Defines all ALP/GraphBLAS descriptors.
RC foldl(IOType &x, const Vector< InputType, backend, Coords > &y, const Vector< MaskType, backend, Coords > &mask, const Monoid &monoid=Monoid(), const typename std::enable_if< !grb::is_object< IOType >::value &&!grb::is_object< InputType >::value &&!grb::is_object< MaskType >::value &&grb::is_monoid< Monoid >::value, void >::type *const =nullptr)
Reduces, or folds, a vector into a scalar.
Definition: blas1.hpp:3840
RC foldr(const Vector< InputType, backend, Coords > &x, const Vector< MaskType, backend, Coords > &mask, IOType &y, const Monoid &monoid=Monoid(), const typename std::enable_if< !grb::is_object< IOType >::value &&!grb::is_object< InputType >::value &&!grb::is_object< MaskType >::value &&grb::is_monoid< Monoid >::value, void >::type *const =nullptr)
Folds a vector into a scalar, right-to-left.
Definition: blas1.hpp:3943
Specifies the ALP algebraic type traits.
The ALP/GraphBLAS namespace.
Definition: graphblas.hpp:477
Indicates the primitive has executed successfully.
Definition: rc.hpp:54
Used to inspect whether a given type is an ALP operator.
Definition: type_traits.hpp:104