-
Notifications
You must be signed in to change notification settings - Fork 5
Introduction to static strides and static extents for static Tensor
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
- 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.
-
Few unnecessary functions and data members related to arrays or not related to tensor. i.e
extent<...>(T*)
,struct mdspan_prop
, etc -
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
- 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 intobasic_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
-
Second problem was easily mitigated as I removed the unused methods and data members
-
For third problem I chose only
extents_impl
,layout_right
andlayout_left
but modified them according to the needs of tensor
- 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*/)
-
Added the support for
static_extents
andstatic_strides
infunctions.hpp
and few other headers -
Few new headers
static_extents.hpp
static_strides.hpp
-
dynamic_strides.hpp
this header containsbasic_extents
-
dynamic_extents.hpp
this header containsbasic_strides
extents_functions.hpp
extents_helper.hpp
shape_helper.hpp
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
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
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 |
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 |
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};
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
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 |
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 |
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 | 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 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
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
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 |
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 |
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 | 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 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
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 |
/**
* ....
* @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;
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
We both would like to thank our mentor Cem for his constant support and help in achieving our goals. We always find him helpful and he was always easy to reach for help or discussion regarding the work. We would also like to thank Google for the Google Summer of Code Programme, without which all these wouldn't be possible. Lastly, we express our gratitude to our parents for helping and providing us with all the indirect or direct needs for carrying out our work nicely in our homes.
- Home
- Project Proposal
- Milestones and Tasks
- Implementation
- Documentation
- Discussions
- Examples
- Experimental features
- Project Proposal
- Milestones and Tasks
- Implementation
- Documentation
- Discussions
- Example Code