Skip to content

Introduction to static strides and static extents for static Tensor

amitsingh19975 edited this page Jun 25, 2019 · 22 revisions

Abstract

Introduction to static strides and static extents is one step closer to making static Tensor which will make Tensor more efficient.

First Cem Bassoy and I decided to integrate kokkos mdspan but the problem with this implementation is that it is made with keeping array in mind as you cannot define how dimensions you required at compile time to do so you have to hard code the extents as you do in arrays and there was few functions used for array manipulation so I had to them because of which it was very difficult to integrate with Tensor. To get rid of the problems I implemented the whole static strides and static extents from ground up for keeping tensor in mind or refactored some part of the code.

Problems with Kokkos mdspan

  1. You cannot create extents with specific size but you have to provide extents which made the construction of static rank but dynamic extents impossible. i.e extents<2,3,4,5>, extents<2,dynamic_extent,4,5>

extents<5> extents of size 5 is not possible with this way so alternative to this in mdspan is extents< dynamic_extent, dynamic_extent, dynamic_extent, dynamic_extent, dynamic_extent > is very haptic for example lets say you want extents with size 100 then you have repeat dynamic_extent for hundred times.

  1. Few unnecessary functions and data members related to arrays or not related to tensor. i.e extent<...>(T*), struct mdspan_prop, etc

  2. Unnecessary code which was not related to tensor such as props, etc. i.e struct slices_impl, struct mdspan_prop, etc

How I mitigated the Problems

  1. Problem related to static rank and dynamic extents, I created shape_helper similar to std::index_sequence which creates the sequence and fills the repeated sequence of -1 with specific size into basic_extents_impl, so now it's possible to specify size at compile time.

i.e

auto s1 = make_basic_shape_t<5>{};// basic_shape<-1,-1,-1,-1,-1>
auto s2 = make_basic_shape_t<3,1,2,3>{};// basic_shape<1,2,3>

You can still use mdspan's way of creating extents for example

auto e1 = basic_static_extents<size_t,4, dynamic_extent, dynamic_extent, dynamic_extent, dynamic_extent >{};
auto e2 = basic_static_extents<size_t,4>{};
auto e3 = dynamic_extents<4>{};// they are equivalent

Advantage of this implementation is that their is size or rank checking and checking for initialising extents

  1. Second problem was easily mitigated as I removed the unused methods and data members

  2. For third problem I chose only extents_impl, layout_right and layout_left but modified them according to the needs of tensor

Changes

  • Removed the functions from current extents and made them free functions
    • valid
    • is_scalar
    • is_vector
    • is_matrix
    • is_tensor
    • squeeze
    • product

So now if you want to use them you have to write your_function(pass_extents)

i.e is_scalar(/*Extents*/)

If you want use both static and dynamic extents use header extents.hpp

Similarly if you want use both static and dynamic strides use header strides.hpp

New To Tensor

  1. basic_extents_impl

It is in detail namespace of ublas and it is an engine for static extents as it has all the logic. It decides how to create the extents with the given parameter pack

Template Parameter

Parameter Description
R Rank of the Extents
S Takes type basic_shape containing extents

Data Member

Member Description Default
Rank Static constexpr member contains rank For empty basic_shape it has value of 0
DynamicRank Static constexpr member contains dynamic rank For empty basic_shape it has value of 0
IsDynamic Static constexpr member checks if it is dynamic or not For empty basic_shape it is false
N Static constexpr member contains extent For empty basic_shape it is 1

Member Functions

  • Construction

Member Functions Description
basic_extents_impl() Default constructor
basic_extents_impl(basic_extents_impl const &) Default copy constructor and copy assignment
basic_extents_impl(std::initializer_list) Construction using initializer_list for dynamic extents
basic_extents_impl(Iterator, Iterator, iterator_tag) Construction using Iteraor for dynamic extents only with value type of integral
  • Element access

Member Functions Description
ptrdiff_t at(int k) Returns the extents at position k
ptrdiff_t operator[](int k) Returns the extents at position k
  • Capacity

Member Functions Description Default
bool empty() Returns true if empty else false
size_t size() Returns number of extents or rank
ptrdiff_t product(int k) Returns product from starting k to the end Returns 1 for empty basic_shape
ptrdiff_t product() Returns product of extents Returns 1 for empty basic_shape
template <ptrdiff_t R, ptrdiff_t... E>
using extents = boost::numeric::ublas::detail::basic_extents_impl<0,boost::numeric::ublas::detail::make_basic_shape_t<R, E...>>;

auto e1 = extents<2,1,2>{};
auto e2 = extents<3,1,3,1>{};
auto e3 = extents<4,1,4,1,1>{};
auto e4 = extents<5,5,1,1,1,1>{};
auto e5 = extents<6>{6,1,1,1,1,1};
  1. static_extents

It helps you to create extents at compile and runtime as you can create whole extents at compile time or create extents at runtime or mix of both but with compile time rank so you cannot change the rank afterwards if you want dynamic rank then choose basic_extents.

Public base class basic_extents_impl<0, make_basic_shape_t<R, E...>>

Template Parameter

Parameter Description
int_type Extents type
E Parameter pack containing extents and Rank

Member Types

Member type Description
base_type Type alias of std::vector<int_type>
array_type Type alias of std::array<int_type,R>
value_type Type of int_type
const_reference Constant reference type base_type
reference Reference type base_type
const_pointer Constant reference type base_type
const_iterator Constant RandomAccessIterator type base_type
size_type std::size_t

Member Functions

  • Construction

Member Functions Description
basic_extents() Default constructor
basic_extents(basic_extents const &) Default copy constructor and copy assignment
basic_extents(value_type extent,IndexType... DynamicExtents) Construction using parameter pack containing extents for dynamic extents
basic_extents(Iterator begin, Iterator end) Construction using Iteraor for dynamic extents only with value type of integral
  • Element access

Member Functions Description
ptrdiff_t at(int k) Returns the extents at position k
ptrdiff_t operator[](int k) Returns the extents at position k
  • Capacity

Member Functions Description
bool empty() Returns true if empty else false
size_t size() Returns number of extents or rank
ptrdiff_t dynamic_rank() Returns number of dynamic extents or dynamic rank
array_type to_array() Returns array containing extents
base_type to_vector() Returns vector containing extents
base_type base() Returns vector containing extents
base_type to_dynamic_extents() Returns dynamic_extents
  • Type Trait

Type Trait Description Template Parameter
template<ptrdiff_t... E> struct dynamic_extents_impl Type trait for selecting either basic_static_extents with dynamic extents or basic_extents E parameter pack containing extents
template <class E> struct is_dynamic Type trait for checking if it is dynamic extents or not E type of extents static_extents</*Extents*/>, dynamic_extents</*Rank*/> and dynamic_extents <>
  • Alias templates

Alias template Description
template<ptrdiff_t...E> static_extents = basic_static_extents<std::size_t,sizeof...(E),E...> Type of basic_static_extents with int_type of std::size_t
template<ptrdiff_t...E> dynamic_extents = typename detail::dynamic_extents_impl<E...>::type Type of basic_static_extents with int_type of std::size_t and dynamic extents and static rank or dynamic rank
  • Different Types of Extents
    • static_extents</*extents*/> => static rank and static extents
    • dynamic_extents</*Rank*/> => static rank and dynamic extents
    • dynamic_extents<> => dynamic rank and dynamic extents
auto e1 = static_extents <1,2>{};
auto e2 = dynamic_extents<3>{1,3,1};
auto e3 = dynamic_extents<>{1,4,1,1};
auto e4 = static_extents <5,1,1,1,1>{};
auto e5 = static_extents<6>{6,1,1,1,1,1}; // dynamic_extents<6>{6,1,1,1,1,1} they both equivalent
  1. static_strides

It helps you to create strides at compile using static_extents

Public base class basic_static_extents<T, R, Extents...>

Template Parameter

Parameter Description
T Extents type
R Rank of extents
Layout Layout of strides
Extents Parameter pack containing extents and Rank

Member Types

Member type Description
extents_type Type alias of basic_static_extents<T, R, Extents...>
base_type Type alias of std::vector<int_type>
layout_type Type alias of Layout either first_order or last_order
value_type Type of int_type
const_reference Constant reference type base_type
reference Reference type base_type
const_pointer Constant reference type base_type
const_iterator Constant RandomAccessIterator type base_type
size_type std::size_t

Member Functions

  • Construction

Member Functions Description
static_strides() Default constructor
static_strides(static_strides const &) Default copy constructor and copy assignment
static_strides(value_type extent,IndexType... DynamicExtents) Construction using parameter pack containing extents for dynamic extents
static_strides(Iterator begin, Iterator end) Construction using Iteraor for dynamic extents only with value type of integral
  • Element access

Member Functions Description
ptrdiff_t at(int k) Returns the stride at position k
ptrdiff_t operator[](int k) Returns the stride at position k
ptrdiff_t extents(int k) Returns the extent at position k
ptrdiff_t stride(int k) Returns the stride at position k
  • Capacity

Member Functions Description
bool empty() Returns true if empty else false
size_t size() Returns size of strides
base_type base() Returns vector containing strides
  • Type Trait

Type Trait Description Template Parameter
template <class E, class Layout> struct stride_type Type trait for selecting static_strides or basic_stride based on the type of extents E type of extents either basic_extents or basic_static_extents and Layout of either first_order or last_order
  • Alias templates

Alias template Description
template <class E, class Layout> using stride_t = typename stride_type<E, Layout>::type Type alias of stride_type<E,Layout>::type
using e1 = static_extents<1,2>;
using e2 = dynamic_extents<3>;
using e3 = dynamic_extents<>;
using e4 = static_extents <5,1,1,1,1>;
using e5 = static_extents<6>; // dynamic_extents<6> they both equivalent

auto s1 = stride_t<e1,first_order>{}; //static_strides
auto s2 = stride_t<e2,first_order>{1,3,1};//static_strides
auto s3 = stride_t<e3,last_order>{dynamic_extents<>{1,4,1,1}};//dynamic strides of type basic_strides
auto s4 = stride_t<e4,last_order>{};//static_strides
auto s5 = stride_t<e4,last_order>{6,1,1,1,1,1};//static_strides
  1. Free Functions for extents

Function Template Function Name Description
template <class E, /enabling_if for extents/> bool valid(E const&) Returns if extents is valid or not
template <class E, /enabling_if for extents/> std::string to_string(E const&) Returns the string representation of extents
template <class E, /enabling_if for extents/> bool is_scalar(E const&) Returns if extents is scalar or not
template <class E, /enabling_if for extents/> bool is_vector(E const&) Returns if extents is vector or not
template <class E, /enabling_if for extents/> bool is_matrixE const&) Returns if extents is matrix or not
template <class E, /enabling_if for extents/> bool is_tensor(E const&) Returns if extents is tensor or not
template <class E, /enabling_if for extents/> basic_extents<T> squeeze(E const&) Returns basic_extents or dynamic_extents<> containing squeezed extents
template <class E, /enabling_if for extents/> size_t product(E const&) Returns the product of extents or total size of the memory needed for storing the tensor

Updated tensor class

/**
* ....
* @tparam E type of basic_extents or static_extents defaults to shape<dynamic_rank>
* ....
*/
template<class T, class E, class F, class A>
class tensor;

Examples

auto t1 = tensor<int>{}; // tensor with dynamic extents and dynamic strides

auto t2 = tensor<int,dynamic_extents<4>>{dynamic_shape<4>{1,2,3,4}}; // tensor with static rank but dynamic extents and static_strides

auto t3 = tensor{dynamic_extents<4>{1,2,3,4},4}; //same as above but with deduction guide

auto t4 = tensor<int,static_extents<1,2,3,4>>{}; // tensor with static rank, static extents and static strides

auto t5 = tensor{shape<4,1,2,3,4>{)}; // if you don't pass second parameter the type will be of float and also using deduction guide
Clone this wiki locally