The dg dispatch system
At the heart of the dispatch system lies the dg::TensorTraits
class that specifies how a type T
behaves in the respective functions though a tag system defined by the tensor_category
tag and the execution_policy
tag. Per default it looks like
template< class T, class Enable=void>
struct TensorTraits
{
};
NoPolicyTag execution_policy
Definition tensor_traits.h:41
NotATensorTag tensor_category
Definition tensor_traits.h:40
void value_type
Definition tensor_traits.h:39
The values for tensor_category
are either dg::NotATensorTag
or (a class derived from) dg::AnyMatrixTag
, while the values for execution_policy
are either dg::NoPolicyTag
or (a class derived from) dg::AnyPolicyTag
. Any type T
assumes the above default values for value_type
, tensor_category
and execution_policy
unless a specialisation exists for that type (see All TensorTraits specialisations for a full list). We define the following nomenclature
When dispatching level 1 functions we distinguish between three classes of functions: trivially parallel (dg::blas1::subroutine
and related dg::blas1
functions), global communication (dg::blas1::dot
and dg::blas2::dot
) and local communication (dg::blas2::symv
).
The subroutine function
The execution of dg::blas1::subroutine
with a Functor called routine
(and all related dg::blas1
functions) is equivalent to the following:
- Assert the following prerequisites:
- All template parameter types must be either Scalars or Vectors and have an execution policy and a value type
- All Vectors and all execution policies must be mutually compatible
- All Vectors must contain the same number of elements (equal sizes)
- The number of template parameters must be equal to the number of parameters in the
routine
- The value type of every template parameter must be convertible to the respective parameter type in the
routine
- If all types are Scalars, apply the
routine
and return
- If at least one type is a Vector, then all Scalars are promoted to this type with the same size, communicator and execution policy
- Check the base class of the tensor_category:
- If
dg::SharedVectorTag
, check execution policy and dispatch to respective implementation (The implementation just loops over all elements in the vectors and applies the routine
)
- If
dg::MPIVectorTag
, access the underlying data and recursively call dg::blas1::subroutine
(and start again at 1)
- If
dg::RecursiveVectorTag
, loop over all elements and recursively call dg::blas1::subroutine
for all elements (and start again at 1)
The dot function
The execution of dg::blas1::dot
and dg::blas2::dot
is equivalent to the following:
- Assert the following prerequisites:
- All template parameter types must be either Scalars or Vectors and have an execution policy and a value type
- All Vectors and all execution policies must be mutually compatible
- All Vectors must contain the same number of elements (equal sizes)
- If all types are Scalars, multiply and return
- If at least one type is a Vector, then all Scalars are promoted to this type with the same size, communicator and execution policy
- Check the base class of the tensor_category:
- If
dg::SharedVectorTag
, check execution policy and dispatch to respective implementation (The implementation multiplies and accumulates all elements in the vectors). Return the result.
- If
dg::MPIVectorTag
, assert that the vector MPI-communicators are congruent
(same process group, different context) or ident
(same process group, same context). Then, access the underlying data and recursively call dot
(and start again at 1). Accumulate the result among participating processes and return.
- If
dg::RecursiveVectorTag
, loop over all elements and recursively call dot
for all elements (and start again at 1). Accumulate the results and return.
The symv function
In the execution of the dg::blas2::symv
(and its aliases dg::blas2::gemv
and dg::apply
) each matrix type has individual prerequisites and execution paths depending on its tensor_category
. We can identify some general rules:
- If the tensor category is
dg::NotATensorTag
(any type has this tag by default unless it is overwritten by a specialization of dg::TensorTraits
) then the compiler assumes that the type is a functor type and immediately forwards all parameters to the operator()
member and none of the following applies
- If the Matrix type has the
dg::SelfMadeMatrixTag
tensor category, then all parameters are immediately forwarded to the symv
member function. No asserts are performed and none of the following applies.
- If the Matrix type is either a Scalar or a Vector and the remaining types do not have the
dg::RecursiveVectorTag
tensor category, then dg::blas2::symv
is equivalent to dg::blas1::pointwiseDot
- The container template parameters must be Vectors or Scalars and must have compatible execution policies. Vectors must be compatible.
- If the tensor category of the Vectors is
dg::RecursiveVectorTag
and the tensor category of the Matrix is not, then the dg::blas2::symv
is recursively called with the Matrix on all elements of the Vectors.
◆ get_execution_policy
◆ get_tensor_category
◆ get_value_type
◆ has_policy
template<class T , class Tag = AnyPolicyTag>
◆ is_matrix
template<class T , class Tag = AnyMatrixTag>
Does a type have a tensor_category derived from Tag
.
- See also
- dg::is_matrix_v
◆ is_scalar
template<class T , class Tag = AnyScalarTag>
Does a type have a tensor_category derived from Tag
.
- See also
- dg::is_scalar_v
◆ is_vector
template<class T , class Tag = AnyVectorTag>
Does a type have a tensor_category derived from Tag
.
- See also
- dg::is_vector_v
◆ has_policy_v
template<class T , class Tag = AnyPolicyTag>
◆ is_matrix_v
template<class T , class Tag = AnyMatrixTag>
bool dg::is_matrix_v = is_matrix<T, Tag>::value |
|
constexpr |
◆ is_scalar_v
template<class T , class Tag = AnyScalarTag>
bool dg::is_scalar_v = is_scalar<T, Tag>::value |
|
constexpr |
◆ is_vector_v
template<class T , class Tag = AnyVectorTag>
bool dg::is_vector_v = is_vector<T, Tag>::value |
|
constexpr |