Skip to content

Instantly share code, notes, and snippets.

@amitsingh19975
Last active April 2, 2020 11:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save amitsingh19975/f92833e284371959ad9d28157fc63fb8 to your computer and use it in GitHub Desktop.
Save amitsingh19975/f92833e284371959ad9d28157fc63fb8 to your computer and use it in GitHub Desktop.
decoupling tensor
int main(){
auto s1 = ub::test::tensor_static_container<float,ub::static_extents<1,2,3>, ub::first_order>{};
auto s2 = ub::test::tensor_static_container<float,ub::static_extents<1,2,3>, ub::first_order>{1};
std::cout<<s1.rank()<<'\n';
return 0;
}
// Copyright (c) 2018-2019
// Cem Bassoy
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// The authors gratefully acknowledge the support of
// Fraunhofer and Google in producing this work
// which started as a Google Summer of Code project.
//
#ifndef BOOST_UBLAS_TENSOR_FUNCTION_HPP
#define BOOST_UBLAS_TENSOR_FUNCTION_HPP
#include "tensor.hpp"
#include <boost/numeric/ublas/tensor/detail/static_extents_traits.hpp>
namespace boost::numeric::ublas::test{
template<class T, class E, class F>
struct tensor_static_container : tensor< tensor_static_container< T,E,F > > {
static_assert( std::is_same<F,first_order>::value ||
std::is_same<F,last_order >::value,
"boost::numeric::tensor template class only supports first- or last-order storage formats.");
using super_type = tensor< tensor_static_container< T, E, F > >;
template<class derived_type>
using tensor_expression_type = typename super_type::template tensor_expression_type<derived_type>;
template<class derived_type>
using matrix_expression_type = typename super_type::template matrix_expression_type<derived_type>;
template<class derived_type>
using vector_expression_type = typename super_type::template vector_expression_type<derived_type>;
using array_type = std::array<T, static_traits::product_v<E> >;
using layout_type = F;
using size_type = typename array_type::size_type;
using difference_type = typename array_type::difference_type;
using value_type = typename array_type::value_type;
using reference = typename array_type::reference;
using const_reference = typename array_type::const_reference;
using pointer = typename array_type::pointer;
using const_pointer = typename array_type::const_pointer;
using iterator = typename array_type::iterator;
using const_iterator = typename array_type::const_iterator;
using reverse_iterator = typename array_type::reverse_iterator;
using const_reverse_iterator = typename array_type::const_reverse_iterator;
using extents_type = E;
using strides_type = strides_t<extents_type,layout_type>;
using matrix_type = matrix<value_type,layout_type,std::vector<value_type>>;
using vector_type = vector<value_type,std::vector<value_type>>;
constexpr tensor_static_container() = default;
constexpr tensor_static_container( array_type const& a )
: super_type(extents_type{}, a)
{}
constexpr tensor_static_container( value_type const& i )
: super_type()
{
std::fill(super_type::begin(), super_type::end(), i);
}
constexpr tensor_static_container( matrix_type const& v )
{
auto const sz = v.size1() * v.size2();
if(sz){
std::copy(v.data().begin(), v.data().end(),super_type::data_.begin());
}
}
constexpr tensor_static_container( matrix_type && v )
{
auto const sz = v.size1() * v.size2();
if(sz){
for(auto i = size_type{}; i < sz; ++i){
super_type::data_[i] = std::move(v.data()[i]);
}
}
}
constexpr tensor_static_container (const vector_type &v){
auto const sz = v.size();
if(sz){
std::copy(v.data().begin(), v.data().end(),super_type::data_.begin());
}
}
constexpr tensor_static_container (vector_type &&v){
auto const sz = v.size();
if(sz){
for(auto i = size_type{}; i < sz; ++i){
super_type::data_[i] = std::move(v.data()[i]);
}
}
}
template<class OtherLayout>
constexpr tensor_static_container (const tensor_static_container<value_type, extents_type, OtherLayout> &expr)
: super_type(static_cast<super_type const&>(expr))
{}
template<class derived_type>
constexpr tensor_static_container (const tensor_expression_type<derived_type> &expr)
: super_type(exp)
{}
template<class derived_type>
constexpr tensor_static_container& operator= (const tensor_expression_type<derived_type> &expr)
{
static_cast<super_type>(*this) = expr;
return *this;
}
template<class derived_type>
constexpr tensor_static_container (const matrix_expression_type<derived_type> &expr)
: super_type(exp)
{}
template<class derived_type>
constexpr tensor_static_container (const vector_expression_type<derived_type> &expr)
: super_type(exp)
{}
};
template<typename T, typename E, typename F>
struct base_traits< tensor_static_container<T,E,F> >{
using value_type = T;
using extents_type = E;
using layout_type = F;
using array_type = std::array<value_type, static_traits::product_v<E>>;
};
} // namespace boost::numeric::ublas::test
template <class C>
std::ostream& operator << (std::ostream& out, boost::numeric::ublas::test::tensor<C> const& t)
{
if(is_scalar(t.extents())){
out << '[';
boost::numeric::ublas::detail::print(out,t[0]);
out << ']';
}
else if(is_vector(t.extents())) {
const auto& cat = t.extents().at(0) > t.extents().at(1) ? ';' : ',';
out << '[';
for(auto i = 0u; i < t.size()-1; ++i){
boost::numeric::ublas::detail::print(out,t[i]);
out << cat << ' ';
}
boost::numeric::ublas::detail::print(out,t[t.size()-1]);
out << ']';
}
else{
boost::numeric::ublas::detail::print(out, t.rank()-1, t.data(), t.strides().data(), t.extents().data());
}
return out;
}
#endif
// Copyright (c) 2018-2019
// Cem Bassoy
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// The authors gratefully acknowledge the support of
// Fraunhofer and Google in producing this work
// which started as a Google Summer of Code project.
//
/// \file tensor.hpp Definition for the tensor template class
#ifndef BOOST_UBLAS_TENSOR_TEST_HPP
#define BOOST_UBLAS_TENSOR_TEST_HPP
#include <initializer_list>
#include <boost/numeric/ublas/tensor/algorithms.hpp>
#include <boost/numeric/ublas/tensor/storage.hpp>
#include <boost/numeric/ublas/tensor/expression.hpp>
#include <boost/numeric/ublas/tensor/expression_evaluation.hpp>
#include <boost/numeric/ublas/tensor/extents.hpp>
#include <boost/numeric/ublas/tensor/strides.hpp>
#include <boost/numeric/ublas/tensor/index.hpp>
#include <boost/numeric/ublas/tensor/detail/type_traits.hpp>
namespace boost { namespace numeric { namespace ublas::test {
template<typename DerivedType>
struct base_traits;
template<typename Container>
class tensor:
public detail::tensor_expression<tensor<Container>,tensor<Container>>
{
using self_type = tensor<Container>;
public:
template<class derived_type>
using tensor_expression_type = detail::tensor_expression<self_type,derived_type>;
template<class derived_type>
using matrix_expression_type = matrix_expression<derived_type>;
template<class derived_type>
using vector_expression_type = vector_expression<derived_type>;
using super_type = tensor_expression_type<self_type>;
using container_type = Container;
using array_type = typename base_traits<container_type>::array_type;
using layout_type = typename base_traits<container_type>::layout_type;
using size_type = typename array_type::size_type;
using difference_type = typename array_type::difference_type;
using value_type = typename array_type::value_type;
using reference = typename array_type::reference;
using const_reference = typename array_type::const_reference;
using pointer = typename array_type::pointer;
using const_pointer = typename array_type::const_pointer;
using iterator = typename array_type::iterator;
using const_iterator = typename array_type::const_iterator;
using reverse_iterator = typename array_type::reverse_iterator;
using const_reverse_iterator = typename array_type::const_reverse_iterator;
using tensor_temporary_type = self_type;
using storage_category = dense_tag;
using extents_type = typename base_traits<container_type>::extents_type;
using strides_type = strides_t<extents_type,layout_type>;
using matrix_type = matrix<value_type,layout_type,std::vector<value_type>>;
using vector_type = vector<value_type,std::vector<value_type>>;
/** @brief Constructs a tensor.
*
* @note the tensor is empty.
* @note the tensor needs to reshaped for further use.
*
*/
inline
constexpr tensor ()
: tensor_expression_type<self_type>() // container_type
, extents_()
, strides_()
{}
/** @brief Constructs a tensor with an initializer list for dynamic_extents
*
* By default, its elements are initialized to 0.
*
* @code tensor<float> A{4,2,3}; @endcode
*
* @param l initializer list for setting the dimension extents of the tensor
*/
explicit inline
tensor (std::initializer_list<size_type> l)
: tensor_expression_type<self_type>()
, extents_ (std::move(l))
, strides_ (extents_)
, data_(product(extents_))
{}
/** @brief Constructs a tensor with a \c shape
*
* By default, its elements are initialized to 0.
*
* @code tensor<float> A{extents{4,2,3}}; @endcode
*
* @param s initial tensor dimension extents
*/
explicit inline
tensor (extents_type const& s)
: tensor_expression_type<self_type>() //tensor_container<self_type>()
, extents_ (s)
, strides_ (extents_)
, data_(product(extents_))
{}
/** @brief Constructs a tensor with a \c shape and initiates it with one-dimensional data
*
* @code tensor<float> A{extents{4,2,3}, array }; @endcode
*
*
* @param s initial tensor dimension extents
* @param a container of \c array_type that is copied according to the storage layout
*/
inline
tensor (extents_type const& s, const array_type &a)
: tensor_expression_type<self_type>() //tensor_container<self_type>()
, extents_ (s)
, strides_ (extents_)
, data_ (a)
{
if(product(extents_) != this->data_.size())
throw std::runtime_error("Error in boost::numeric::ublas::tensor: size of provided data and specified extents do not match.");
}
/** @brief Constructs a tensor using a shape tuple and initiates it with a value.
*
* @code tensor<float> A{extents{4,2,3}, 1 }; @endcode
*
* @param e initial tensor dimension extents
* @param i initial value of all elements of type \c value_type
*/
inline
tensor (extents_type const& e, const value_type &i)
: tensor_expression_type<self_type>() //tensor_container<self_type> ()
, extents_ (e)
, strides_ (extents_)
, data_(product(extents_), i)
{}
// /** @brief Constructs a tensor using a shape tuple and initiates it with a value.
// *
// * @code tensor<float> A{extents{4,2,3}, 1 }; @endcode
// *
// * @param e initial tensor dimension extents
// * @param i initial value of all elements of type \c value_type
// */
// template<class U = E>
// inline
// tensor (shape_t<typename extents_type::value_type, dynamic_rank> const& e, const value_type &i, typename std::enable_if<detail::is_static_extents<U>::value>::type* = nullptr)
// : tensor_expression_type<self_type>() //tensor_container<self_type> ()
// , extents_ (e.begin(),e.end())
// , strides_ (extents_)
// , data_ (product(extents_), i)
// {}
/** @brief Constructs a tensor from another tensor
*
* @param v tensor to be copied.
*/
inline
tensor (const tensor &v)
: tensor_expression_type<self_type>()
, extents_ (v.extents_)
, strides_ (v.strides_)
, data_ (v.data_ )
{}
/** @brief Constructs a tensor from another tensor
*
* @param v tensor to be moved.
*/
inline
tensor (tensor &&v)
: tensor_expression_type<self_type>() //tensor_container<self_type> ()
, extents_ (std::move(v.extents_))
, strides_ (std::move(v.strides_))
, data_ (std::move(v.data_ ))
{}
/** @brief Constructs a tensor with a matrix
*
* \note Initially the tensor will be two-dimensional.
*
* @param v matrix to be copied.
*/
inline
tensor (const matrix_type &v)
: tensor_expression_type<self_type>()
, extents_ ()
, strides_ ()
{}
/** @brief Constructs a tensor using a \c vector
*
* @note It is assumed that vector is column vector
* @note Initially the tensor will be one-dimensional.
*
* @param v vector to be copied.
*/
inline
tensor (const vector_type &v)
: tensor_expression_type<self_type>()
, tensor()
{
auto const sz = v.size();
if(sz){
std::copy(v.data().begin(), v.data().end(),data_.begin());
}
}
/** @brief Constructs a tensor using a \c vector
*
* @param v vector to be moved.
*/
inline
tensor (vector_type &&v)
: tensor_expression_type<self_type>()
, extents_ {}
, strides_ {}
, data_ {}
{
auto const sz = v.size();
if(sz){
for(auto i = size_type{}; i < sz; ++i){
data_[i] = std::move(v.data()[i]);
}
}
}
/** @brief Constructs a tensor with another tensor with a different layout
*
* @param other tensor with a different layout to be copied.
*/
template<class OtherContainer>
tensor (const tensor<OtherContainer> &other)
: tensor_expression_type<self_type> ()
, extents_ (other.extents())
, strides_ (other.extents())
{
copy(this->rank(), this->extents().data(),
this->data(), this->strides().data(),
other.data(), other.strides().data());
}
/** @brief Constructs a tensor with an tensor expression
*
* @code tensor<float> A = B + 3 * C; @endcode
*
* @note type must be specified of tensor must be specified.
* @note dimension extents are extracted from tensors within the expression.
*
* @param expr tensor expression
*/
template<class derived_type>
tensor (const tensor_expression_type<derived_type> &expr)
: tensor_expression_type<self_type> ()
, extents_ ( detail::retrieve_extents(expr) )
, strides_ ( extents_ )
{
detail::eval( *this, expr );
}
/** @brief Constructs a tensor with a matrix expression
*
* @code tensor<float> A = B + 3 * C; @endcode
*
* @note matrix expression is evaluated and pushed into a temporary matrix before assignment.
* @note extents are automatically extracted from the temporary matrix
*
* @param expr matrix expression
*/
template<class derived_type>
tensor (const matrix_expression_type<derived_type> &expr)
: tensor( matrix_type ( expr ) )
{
}
/** @brief Constructs a tensor with a vector expression
*
* @code tensor<float> A = b + 3 * b; @endcode
*
* @note matrix expression is evaluated and pushed into a temporary matrix before assignment.
* @note extents are automatically extracted from the temporary matrix
*
* @param expr vector expression
*/
template<class derived_type>
tensor (const vector_expression_type<derived_type> &expr)
: tensor( vector_type ( expr ) )
{
}
/** @brief Evaluates the tensor_expression and assigns the results to the tensor
*
* @code A = B + C * 2; @endcode
*
* @note rank and dimension extents of the tensors in the expressions must conform with this tensor.
*
* @param expr expression that is evaluated.
*/
template<class derived_type>
tensor &operator = (const tensor_expression_type<derived_type> &expr)
{
detail::eval(*this, expr);
return *this;
}
tensor& operator=(tensor other)
{
swap (*this, other);
return *this;
}
tensor& operator=(const_reference v)
{
std::fill(this->begin(), this->end(), v);
return *this;
}
/** @brief Returns true if the tensor is empty (\c size==0) */
inline
bool empty () const {
return this->data_.empty();
}
/** @brief Returns the size of the tensor */
inline
size_type size () const {
return this->data_.size ();
}
/** @brief Returns the size of the tensor */
inline
size_type size (size_type r) const {
return this->extents_.at(r);
}
/** @brief Returns the number of dimensions/modes of the tensor */
inline
size_type rank () const {
return this->extents_.size();
}
/** @brief Returns the number of dimensions/modes of the tensor */
inline
size_type order () const {
return this->extents_.size();
}
/** @brief Returns the strides of the tensor */
inline
strides_type const& strides () const {
return this->strides_;
}
/** @brief Returns the extents of the tensor */
inline
extents_type const& extents () const {
return this->extents_;
}
/** @brief Returns a \c const reference to the container. */
inline
const_pointer data () const {
return this->data_.data();
}
/** @brief Returns a \c const reference to the container. */
inline
pointer data () {
return this->data_.data();
}
/** @brief Element access using a single index.
*
* @code auto a = A[i]; @endcode
*
* @param i zero-based index where 0 <= i < this->size()
*/
inline
const_reference operator [] (size_type i) const {
return this->data_[i];
}
/** @brief Element access using a single index.
*
* @code auto a = A[i]; @endcode
*
* @param i zero-based index where 0 <= i < this->size()
*/
inline
reference operator [] (size_type i) {
return this->data_[i];
}
/** @brief Element access using a multi-index or single-index.
*
*
* @code auto a = A.at(i,j,k); @endcode or
* @code auto a = A.at(i); @endcode
*
* @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0)
* @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank()
*/
template<class ... size_types>
inline
const_reference at (size_type i, size_types ... is) const {
if constexpr (sizeof...(is) == 0)
return this->data_[i];
else
return this->data_[detail::access<0ul>(size_type(0),this->strides_,i,std::forward<size_types>(is)...)];
}
/** @brief Element access using a multi-index or single-index.
*
*
* @code A.at(i,j,k) = a; @endcode or
* @code A.at(i) = a; @endcode
*
* @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0)
* @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank()
*/
template<class ... size_types>
inline
reference at (size_type i, size_types ... is) {
if constexpr (sizeof...(is) == 0)
return this->data_[i];
else{
auto temp = detail::access<0ul>(size_type(0),this->strides_,i,std::forward<size_types>(is)...);
return this->data_[temp];
}
}
/** @brief Element access using a single index.
*
*
* @code A(i) = a; @endcode
*
* @param i zero-based index where 0 <= i < this->size()
*/
inline
const_reference operator()(size_type i) const {
return this->data_[i];
}
/** @brief Element access using a single index.
*
* @code A(i) = a; @endcode
*
* @param i zero-based index where 0 <= i < this->size()
*/
inline
reference operator()(size_type i){
return this->data_[i];
}
/** @brief Generates a tensor index for tensor contraction
*
*
* @code auto Ai = A(_i,_j,k); @endcode
*
* @param i placeholder
* @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank()
*/
template<std::size_t I, class ... index_types>
inline
decltype(auto) operator() (index::index_type<I> p, index_types ... ps) const
{
constexpr auto N = sizeof...(ps)+1;
if( N != this->rank() )
throw std::runtime_error("Error in boost::numeric::ublas::operator(): size of provided index_types does not match with the rank.");
return std::make_pair( std::cref(*this), std::make_tuple( p, std::forward<index_types>(ps)... ) );
}
/** @brief Reshapes the tensor
*
*
* (1) @code A.reshape(extents{m,n,o}); @endcode or
* (2) @code A.reshape(extents{m,n,o},4); @endcode
*
* If the size of this smaller than the specified extents than
* default constructed (1) or specified (2) value is appended.
*
* @note rank of the tensor might also change.
*
* @param e extents with which the tensor is reshaped.
* @param v value which is appended if the tensor is enlarged.
*/
inline
void reshape (extents_type const& e, value_type v = value_type{})
{
static_assert(detail::is_dynamic_v<extents_type>,
"Error in boost::numeric::ublas::tensor: static extents cannot be reshaped");
this->extents_ = e;
this->strides_ = strides_type(this->extents_);
if(product(e) != this->size())
this->data_.resize (product(extents_), v);
}
friend void swap(tensor& lhs, tensor& rhs) {
std::swap(lhs.data_ , rhs.data_ );
std::swap(lhs.extents_, rhs.extents_);
std::swap(lhs.strides_, rhs.strides_);
}
/// \brief return an iterator on the first element of the tensor
inline
const_iterator begin () const {
return data_.begin ();
}
/// \brief return an iterator on the first element of the tensor
inline
const_iterator cbegin () const {
return data_.cbegin ();
}
/// \brief return an iterator after the last element of the tensor
inline
const_iterator end () const {
return data_.end();
}
/// \brief return an iterator after the last element of the tensor
inline
const_iterator cend () const {
return data_.cend ();
}
/// \brief Return an iterator on the first element of the tensor
inline
iterator begin () {
return data_.begin();
}
/// \brief Return an iterator at the end of the tensor
inline
iterator end () {
return data_.end();
}
/// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor)
inline
const_reverse_iterator rbegin () const {
return data_.rbegin();
}
/// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor)
inline
const_reverse_iterator crbegin () const {
return data_.crbegin();
}
/// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor)
inline
const_reverse_iterator rend () const {
return data_.rend();
}
/// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor)
inline
const_reverse_iterator crend () const {
return data_.crend();
}
/// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor)
inline
reverse_iterator rbegin () {
return data_.rbegin();
}
/// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor)
inline
reverse_iterator rend () {
return data_.rend();
}
#if 0
// -------------
// Serialization
// -------------
/// Serialize a tensor into and archive as defined in Boost
/// \param ar Archive object. Can be a flat file, an XML file or any other stream
/// \param file_version Optional file version (not yet used)
template<class Archive>
void serialize(Archive & ar, const unsigned int /* file_version */){
ar & serialization::make_nvp("data",data_);
}
#endif
// private:
extents_type extents_;
strides_type strides_;
array_type data_;
};
}}} // namespaces
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment