tensor.hpp

This header file provides the Tensor class.

Classes and Types

template<class ValueType, bool own_data, Long... Args>
class Tensor

A template class representing a multidimensional tensor. The data is stored in row-major order.

Template Parameters:
  • ValueType – The type of the elements stored in the tensor.

  • own_data – A boolean indicating whether the tensor owns its data.

  • Args – The dimensions of the tensor.

Constructor:

  • Tensor(): Constructs an empty tensor.

  • Tensor(src_iter): Constructs a tensor from an iterator.

  • Tensor(M): Copy constructor.

  • Tensor(v): Constructs a tensor with all elements initialized to a specific value.

Methods:

  • operator=: Copy assignment operator.

  • operator=: Assignment operator setting all elements to a scalar value.

  • Order(): Get the order of the tensor.

  • Size(): Get the total number of elements in the tensor.

  • Dim<k>(): Get the size of a specific dimension of the tensor.

  • begin(): Get an iterator to the beginning of the tensor.

  • end(): Get an iterator to the end of the tensor.

  • operator(): Access a specific element of the tensor.

  • RotateLeft() const: Rotate tensor dimensions to the left.

  • RotateRight() const: Rotate tensor dimensions to the right.

  • operator+(), operator-(): Unary operators.

  • operator+, operator-, operator*, operator/: Element-wise arithmetic operations with a scalar.

  • operator+, operator-: Element-wise arithmetic operations with another tensor with the same dimensions.

  • operator*: Matrix multiplication of two second order tensors.

Usage guide: Using Tensor class



#ifndef _SCTL_TENSOR_HPP_
#define _SCTL_TENSOR_HPP_

#include <ostream>                // for ostream
#include <initializer_list>       // for initializer_list

#include "sctl/common.hpp"        // for Long, Integer, sctl
#include "sctl/static-array.hpp"  // for StaticArray

namespace sctl {

  template <Long k, Long d0, Long... dd> static constexpr Long TensorArgExtract();
  template <class ValueType, bool own_data, Long... dd> struct TensorRotateLeftType;
  template <class ValueType, bool own_data, Long... dd> struct TensorRotateRightType;

  /**
   * A template class representing a multidimensional tensor.
   * The data is stored in row-major order.
   *
   * @tparam ValueType The type of the elements stored in the tensor.
   * @tparam own_data A boolean indicating whether the tensor owns its data.
   * @tparam Args The dimensions of the tensor.
   */
  template <class ValueType, bool own_data, Long... Args> class Tensor {
    public:
      /**
       * Get the order of the tensor.
       *
       * @return The order of the tensor.
       */
      [[nodiscard]] static constexpr Long Order();

      /**
       * Get the total number of elements in the tensor.
       *
       * @return The total number of elements in the tensor.
       */
      [[nodiscard]] static constexpr Long Size();

      /**
       * Get the size of a specific dimension of the tensor.
       *
       * @tparam k The index of the dimension.
       * @return The size of the specified dimension.
       */
      template <Long k> [[nodiscard]] static constexpr Long Dim();

      /**
       * A static function to test the functionality of the Tensor class.
       */
      static void test();

      // Constructor and Destructor

      /**
       * Default constructor.
       *
       * Constructs an empty tensor.
       */
      Tensor();

      /**
       * Constructor initializing tensor from an iterator.
       *
       * @param src_iter Iterator pointing to the beginning of data to initialize the tensor.
       */
      explicit Tensor(Iterator<ValueType> src_iter);

      /**
       * Constructor initializing tensor from a const iterator.
       *
       * @param src_iter Const iterator pointing to the beginning of data to initialize the tensor.
       */
      explicit Tensor(ConstIterator<ValueType> src_iter);

      /**
       * Constructor with initializer list.
       *
       * @param arr An initializer list to initialize the tensor.
       */
      explicit Tensor(std::initializer_list<ValueType> arr);

      /**
       * Copy constructor.
       *
       * @param M Another tensor to copy from.
       */
      Tensor(const Tensor &M);

      /**
       * Constructor initializing all elements of the tensor with a specific value.
       *
       * @param v The value to initialize all elements of the tensor with.
       */
      explicit Tensor(const ValueType& v);

      /**
       * Constructor converting tensor of another data type.
       *
       * @tparam own_data_ Boolean indicating whether the new tensor owns its data.
       * @param M Another tensor to copy from.
       */
      template <bool own_data_> Tensor(const Tensor<ValueType, own_data_, Args...> &M);

      /**
       * Destructor.
       */
      ~Tensor() = default;

      // Assignment Operator

      /**
       * Copy assignment operator.
       *
       * @param M Another tensor to copy from.
       * @return Reference to this tensor.
       */
      Tensor &operator=(const Tensor &M);

      /**
       * Assignment operator setting all elements of the tensor to a specific value.
       *
       * @param v The value to set all elements of the tensor to.
       * @return Reference to this tensor.
       */
      Tensor &operator=(const ValueType& v);

      /**
       * Copy assignment operator from another type.
       *
       * @param M Another tensor to copy from.
       * @return Reference to this tensor.
       */
      template <bool own_data_> Tensor &operator=(const Tensor<ValueType, own_data_, Args...> &M);

      // Member Functions

      /**
       * Get an iterator to the beginning of the tensor.
       *
       * @return An iterator to the beginning of the tensor.
       */
      [[nodiscard]] Iterator<ValueType> begin();

      /**
       * Get a const iterator to the beginning of the tensor.
       *
       * @return A const iterator to the beginning of the tensor.
       */
      [[nodiscard]] ConstIterator<ValueType> begin() const;

      /**
       * Get an iterator to the end of the tensor.
       *
       * @return An iterator to the end of the tensor.
       */
      [[nodiscard]] Iterator<ValueType> end();

      /**
       * Get a const iterator to the end of the tensor.
       *
       * @return A const iterator to the end of the tensor.
       */
      [[nodiscard]] ConstIterator<ValueType> end() const;

      /**
       * Access a specific element of the tensor.
       *
       * @tparam PackedLong Variadic template parameter for the indices of the element.
       * @param ii Indices of the element.
       * @return Reference to the element.
       */
      template <class ...PackedLong> ValueType& operator()(PackedLong... ii);

      /**
       * Access a specific element of the tensor.
       *
       * @tparam PackedLong Variadic template parameter for the indices of the element.
       * @param ii Indices of the element.
       * @return Copy of the element.
       */
      template <class ...PackedLong> const ValueType& operator()(PackedLong... ii) const;

      /**
       * Returns a new tensor obtained by rotating the dimensions of the current tensor to the left.
       * This operation shifts the dimensions of the tensor. If the original tensor has dimensions n1 x n2 x n3,
       * then the left-rotated tensor will be of dimensions n2 x n3 x n1 and the data will be rearranged in a similar way.
       * This operation is a generalization of the transpose operation for matrices.
       *
       * @return A new tensor with dimensions rotated to the left.
       */
      [[nodiscard]] typename TensorRotateLeftType<ValueType, true, Args...>::Value RotateLeft() const;

      /**
       * Returns a new tensor obtained by rotating the dimensions of the current tensor to the right.
       * This operation shifts the dimensions of the tensor. If the original tensor has dimensions n1 x n2 x n3,
       * then the right-rotated tensor will be of dimensions n3 x n1 x n2 and the data will be rearranged accordingly.
       * This operation is a generalization of the transpose operation for matrices.
       *
       * @return A new tensor with dimensions rotated to the right.
       */
      [[nodiscard]] typename TensorRotateRightType<ValueType, true, Args...>::Value RotateRight() const;

      /**
       * Unary positive operator.
       *
       * @return The tensor itself.
       */
      [[nodiscard]] Tensor<ValueType, true, Args...> operator+() const;

      /**
       * Unary negative operator.
       *
       * @return Negated tensor.
       */
      [[nodiscard]] Tensor<ValueType, true, Args...> operator-() const;

      /**
       * Addition operator.
       *
       * @param s Scalar value to add to the tensor.
       * @return Result of addition.
       */
      [[nodiscard]] Tensor<ValueType, true, Args...> operator+(const ValueType &s) const;

      /**
       * Subtraction operator.
       *
       * @param s Scalar value to subtract from the tensor.
       * @return Result of subtraction.
       */
      [[nodiscard]] Tensor<ValueType, true, Args...> operator-(const ValueType &s) const;

      /**
       * Multiplication operator.
       *
       * @param s Scalar value to multiply the tensor by.
       * @return Result of multiplication.
       */
      [[nodiscard]] Tensor<ValueType, true, Args...> operator*(const ValueType &s) const;

      /**
       * Division operator.
       *
       * @param s Scalar value to divide the tensor by.
       * @return Result of division.
       */
      [[nodiscard]] Tensor<ValueType, true, Args...> operator/(const ValueType &s) const;

      /**
       * Addition operator.
       *
       * @tparam own_data_ Boolean indicating whether the resulting tensor owns its data.
       * @param M2 Another tensor to add.
       * @return Result of addition.
       */
      template <bool own_data_> [[nodiscard]] Tensor<ValueType, true, Args...> operator+(const Tensor<ValueType, own_data_, Args...> &M2) const;

      /**
       * Subtraction operator.
       *
       * @tparam own_data_ Boolean indicating whether the resulting tensor owns its data.
       * @param M2 Another tensor to subtract.
       * @return Result of subtraction.
       */
      template <bool own_data_> [[nodiscard]] Tensor<ValueType, true, Args...> operator-(const Tensor<ValueType, own_data_, Args...> &M2) const;

      /**
       * Multiplication operator.
       *
       * This is matrix multiplication. The second tensor should have dimensions compatible with the first.
       *
       * @tparam own_data_ Boolean indicating whether the resulting tensor owns its data.
       * @tparam N1 The size of the second dimension of the first tensor.
       * @tparam N2 The size of the second dimension of the second tensor.
       * @param M2 Another tensor to multiply.
       * @return Result of multiplication.
       */
      template <bool own_data_, Long N1, Long N2> [[nodiscard]] Tensor<ValueType, true, TensorArgExtract<0, Args...>(), N2> operator*(const Tensor<ValueType, own_data_, N1, N2> &M2) const;

    private:

      template <Integer k> static Long offset();

      template <Integer k, class ...PackedLong> static Long offset(Long i, PackedLong... ii);

      void Init(Iterator<ValueType> src_iter);

      StaticArray<ValueType, own_data ? Size() : 0> buff;
      StaticArray<Iterator<ValueType>, own_data ? 0 : 1> iter_;
  };

  template <class ValueType, bool own_data, Long N1, Long N2> std::ostream& operator<<(std::ostream &output, const Tensor<ValueType, own_data, N1, N2> &M);

}  // end namespace

#endif // _SCTL_TENSOR_HPP_