48#include <initializer_list>
114 nelements_ = std::accumulate(shape_.
begin(), shape_.
end(), 1ULL, std::multiplies<>{});
130 std::size_t expected = 1;
131 for (std::size_t dimension = 0; dimension <
rank(); ++dimension) {
132 std::size_t index =
rank() - 1 - dimension;
133 if (strides_[index] != expected) {
134 is_contiguous_ =
false;
136 nelements_ *= shape_[index];
137 expected *= shape_[index];
147 template <Expression Expression>
149 *
this = expression.forward();
158 template <Expression Expression>
175 return shape_.
rank();
185 return shape_[dimension];
205 return nbytesof(dtype_, nelements_);
210 return is_contiguous_;
214 return (nelements_ == 1);
248 return static_cast<std::byte*
>(buffer_->address()) + offset_;
256 return buffer_ ? true :
false;
266 throw Exception(
"Cannot get resource of an initializer tensor.");
267 return buffer_->environment();
288 Tensor(std::initializer_list<T>
const& values)
290 , shape_({values.size()})
293 , nelements_(shape_[0]) {
294 if (dtype_ ==
boolean) {
296 std::ptrdiff_t index = 0;
297 for (
auto const& value : values) {
298 assign((
bool const*)(&value), index);
306 for (
auto const& value : values) {
332 Tensor(std::initializer_list<std::initializer_list<T>>
const& values)
334 , shape_({values.size(), values.begin()->size()})
337 , nelements_(shape_[0] * shape_[1])
340 if (dtype_ ==
boolean) {
342 std::ptrdiff_t index = 0;
343 for (
auto const& row : values) {
344 if (row.size() != shape_[1])
345 throw Exception(
"All rows must have the same number of columns");
346 for (
auto const& value : row) {
347 assign((
bool const*)(&value), index);
356 for (
auto row : values) {
357 if (row.size() != shape_[1])
358 throw Exception(
"All rows must have the same number of columns");
359 for (
auto const& value : row) {
393 Tensor(std::initializer_list<std::initializer_list<std::initializer_list<T>>>
const& values)
395 , shape_({values.size(), values.begin()->size(), values.begin()->begin()->size()})
398 , nelements_(shape_[0] * shape_[1] * shape_[2])
401 if (dtype_ ==
boolean) {
403 std::ptrdiff_t index = 0;
404 for (
auto const& matrix : values) {
405 if (matrix.size() != shape_[1])
406 throw Exception(
"All matrices must have the same number of rows");
407 for (
auto const& row : matrix) {
408 if (row.size() != shape_[2])
409 throw Exception(
"All rows must have the same number of columns");
410 for (
auto const& value : row) {
411 assign((
bool const*)(&value), index);
421 for (
auto const& matrix : values) {
422 if (matrix.size() != shape_[1])
423 throw Exception(
"All matrices must have the same number of rows");
424 for (
auto const& row : matrix) {
425 if (row.size() != shape_[2])
426 throw Exception(
"All rows must have the same number of columns");
427 for (
auto const& value : row) {
474 Tensor(std::initializer_list<std::initializer_list<std::initializer_list<std::initializer_list<T>>>>
const& values)
478 values.begin()->size(),
479 values.begin()->begin()->size(),
480 values.begin()->begin()->begin()->size()
484 , nelements_(shape_[0] * shape_[1] * shape_[2] * shape_[3])
487 if (dtype_ ==
boolean) {
489 std::ptrdiff_t index = 0;
490 for (
auto const& tensor3D : values) {
491 if (tensor3D.size() != shape_[1])
492 throw Exception(
"All 3D tensors must have the same number of matrices");
493 for (
auto const& matrix : tensor3D) {
494 if (matrix.size() != shape_[2])
495 throw Exception(
"All matrices must have the same number of rows");
496 for (
auto const& row : matrix) {
497 if (row.size() != shape_[3])
498 throw Exception(
"All rows must have the same number of columns");
499 for (
auto const& value : row) {
500 assign((
bool const*)(&value), index);
512 for (
auto const& tensor3D : values) {
513 if (tensor3D.size() != shape_[1])
514 throw Exception(
"All 3D tensors must have the same number of matrices");
515 for (
auto const& matrix : tensor3D) {
516 if (matrix.size() != shape_[2])
517 throw Exception(
"All matrices must have the same number of rows");
518 for (
auto const& row : matrix) {
519 if (row.size() != shape_[3])
520 throw Exception(
"All rows must have the same number of columns");
521 for (
auto const& value : row) {
560 throw Exception(
"Assign to initializer list supported only for contiguous tensors");
562 if (
rank() != 1 || shape_[0] != values.size())
563 throw Exception(
"Shape mismatch in assignment from initializer_list");
568 if (dtype_ ==
boolean) {
569 std::ptrdiff_t index = 0;
570 for (
auto const& value : values) {
571 assign((
bool const*)(&value), index);
577 auto fill = [
this, &values](
auto cast) {
578 using Cast =
decltype(cast);
580 for (
auto value : values) {
581 if constexpr (std::is_same_v<Cast, float16_t>) {
582 float as_float = value;
583 float16_t casted = float32_to_float16(as_float);
594 case int8: fill(int8_t{});
break;
595 case int16: fill(int16_t{});
break;
596 case int32: fill(int32_t{});
break;
597 case int64: fill(int64_t{});
break;
598 case float16: fill(float16_t{});
break;
599 case float32: fill(
float{});
break;
600 case float64: fill(
double{});
break;
601 default:
throw Exception(
"Unsupported dtype in assignment");
635 throw Exception(
"Assign to initializer list supported only for contiguous tensors");
637 if (
rank() != 2 || shape_[0] != values.size() || shape_[1] != values.begin()->size())
638 throw Exception(
"Shape mismatch in assignment from nested initializer_list");
643 if (dtype_ ==
boolean) {
644 std::ptrdiff_t index = 0;
645 for (
auto const& row : values) {
646 if (row.size() != shape_[1])
647 throw Exception(
"Row length mismatch in assignment from initializer_list");
648 for (
auto const& value : row) {
649 assign((
bool const*)(&value), index);
656 auto fill = [
this, &values](
auto cast) {
657 using Cast =
decltype(cast);
659 for (
auto const& row : values) {
660 if (row.size() != shape_[1])
661 throw Exception(
"Row length mismatch in assignment from initializer_list");
663 for (
auto value : row) {
664 if constexpr (std::is_same_v<Cast, float16_t>) {
665 float as_float = value;
666 float16_t casted = float32_to_float16(as_float);
678 case int8: fill(int8_t{});
break;
679 case int16: fill(int16_t{});
break;
680 case int32: fill(int32_t{});
break;
681 case int64: fill(int64_t{});
break;
682 case float16: fill(float16_t{});
break;
683 case float32: fill(
float{});
break;
684 case float64: fill(
double{});
break;
685 default:
throw Exception(
"Unsupported dtype in assignment");
725 throw Exception(
"Assign to initializer list supported only for contiguous tensors");
728 || shape_[0] != values.size()
729 || shape_[1] != values.begin()->size()
730 || shape_[2] != values.begin()->begin()->size())
731 throw Exception(
"Shape mismatch in assignment from triple-nested initializer_list");
736 if (dtype_ ==
boolean) {
737 std::ptrdiff_t index = 0;
738 for (
auto const& matrix : values) {
739 if (matrix.size() != shape_[1])
740 throw Exception(
"Matrix row count mismatch");
741 for (
auto const& row : matrix) {
742 if (row.size() != shape_[2])
744 for (
auto const& value : row) {
745 assign((
bool const*)(&value), index);
753 auto fill = [
this, &values](
auto cast) {
754 using Cast =
decltype(cast);
756 for (
auto const& matrix : values) {
757 if (matrix.size() != shape_[1])
758 throw Exception(
"Matrix row count mismatch");
759 for (
auto const& row : matrix) {
760 if (row.size() != shape_[2])
761 throw Exception(
"Row length mismatch");
762 for (
auto value : row) {
763 if constexpr (std::is_same_v<Cast, float16_t>) {
764 float as_float = value;
765 float16_t casted = float32_to_float16(as_float);
778 case int8: fill(int8_t{});
break;
779 case int16: fill(int16_t{});
break;
780 case int32: fill(int32_t{});
break;
781 case int64: fill(int64_t{});
break;
782 case float16: fill(float16_t{});
break;
783 case float32: fill(
float{});
break;
784 case float64: fill(
double{});
break;
785 default:
throw Exception(
"Unsupported dtype in assignment");
833 throw Exception(
"Assign to initializer list supported only for contiguous tensors");
836 || shape_[0] != values.size()
837 || shape_[1] != values.begin()->size()
838 || shape_[2] != values.begin()->begin()->size()
839 || shape_[3] != values.begin()->begin()->begin()->size())
840 throw Exception(
"Shape mismatch in assignment from quadruple-nested initializer_list");
845 if (dtype_ ==
boolean) {
846 std::ptrdiff_t index = 0;
847 for (
auto const& tensor3D : values) {
848 if (tensor3D.size() != shape_[1])
849 throw Exception(
"3D tensor count mismatch");
851 for (
auto const& matrix : tensor3D) {
852 if (matrix.size() != shape_[2])
853 throw Exception(
"Matrix row count mismatch");
855 for (
auto const& row : matrix) {
856 if (row.size() != shape_[3])
859 for (
auto const& value : row) {
860 assign((
bool const*)(&value), index);
869 auto fill = [
this, &values](
auto cast) {
870 using Cast =
decltype(cast);
872 for (
auto const& tensor3D : values) {
873 if (tensor3D.size() != shape_[1])
874 throw Exception(
"3D tensor count mismatch");
876 for (
auto const& matrix : tensor3D) {
877 if (matrix.size() != shape_[2])
878 throw Exception(
"Matrix row count mismatch");
880 for (
auto const& row : matrix) {
881 if (row.size() != shape_[3])
882 throw Exception(
"Row length mismatch");
884 for (
auto value : row) {
885 if constexpr (std::is_same_v<Cast, float16_t>) {
886 float as_float = value;
887 float16_t casted = float32_to_float16(as_float);
901 case int8: fill(int8_t{});
break;
902 case int16: fill(int16_t{});
break;
903 case int32: fill(int32_t{});
break;
904 case int64: fill(int64_t{});
break;
905 case float16: fill(float16_t{});
break;
906 case float32: fill(
float{});
break;
907 case float64: fill(
double{});
break;
908 default:
throw Exception(
"Unsupported dtype in assignment");
940 template<Integral Index>
984 template<
class ... Indexes>
1077 , buffer_(std::move(storage))
1079 nelements_ = std::accumulate(shape_.begin(), shape_.end(), 1ULL, std::multiplies<>{});
1080 node_ = std::make_shared<Node>(*
this);
1088 , buffer_(std::move(storage))
1090 std::size_t expected = 1;
1091 for (std::size_t dimension = 0; dimension <
rank(); ++dimension) {
1092 std::size_t index =
rank() - 1 - dimension;
1093 if (strides_[index] != expected) {
1094 is_contiguous_ =
false;
1096 nelements_ *= shape_[index];
1097 expected *= shape_[index];
1099 node_ = std::make_shared<Node>(*
this);
1103 template <
Expression Source,
class... Indexes>
1106 template <Expression Source>
1109 template <Expression Source>
1112 template <Expression Source>
1115 template <Expression Source>
1121 template <Expression Source>
1124 template <Expression Source>
1127 template <
class Coordinates,
Expression... Sources>
1130 template <Expression Source>
1133 void assign(std::byte
const*, std::ptrdiff_t);
1136 bool compare(std::byte
const*, std::ptrdiff_t)
const;
1152 std::size_t nelements_ = 1;
1153 std::ptrdiff_t offset_ = 0;
1154 mutable std::shared_ptr<Buffer> buffer_ =
nullptr;
1155 mutable std::shared_ptr<Node> node_ =
nullptr;
1156 bool is_contiguous_ =
true;
1161template<Expression Source>
1162inline std::ostream&
operator<<(std::ostream& ostream, Source source) {
1168template<
class Operation, Expression Operand>
1170 Tensor result(dtype(), shape(), strides(), offset());
1171 operation.forward(operand, result);
1175template<Operator Operation, Expression Operand, Expression Cooperand>
1177 Tensor result(dtype(), shape(), strides());
1178 operation.forward(operand, cooperand, result);
1182template<Expression Source>
1185 return Tensor(dtype(), shape(), strides(), offset(), source.buffer_);
1188template<Expression Source>
1191 return Tensor(dtype(), shape(), strides(), offset(), source.buffer_);
1194template<Expression Source>
1197 return Tensor(dtype(), shape(), strides(), offset(), source.buffer_);
1200template<Expression Source>
1203 return Tensor(dtype(), shape(), strides(), offset(), source.buffer_);
1209 return Tensor(dtype(), shape(), strides(), offset(), source.buffer_);
1212template<Expression Source>
1215 return Tensor(dtype(), shape(), strides(), offset(), source.buffer_);
1218template<Expression Source>
1221 return Tensor(dtype(), shape(), strides(), offset(), source.buffer_);
1227 return Tensor(dtype(), shape(), strides(), offset(), source.buffer_);
1233 source_.assign(value, offset);
1237 Tensor tensor = forward();
1238 tensor.
assign(value, offset);
1245 source_.assign(value, offset);
1249 Tensor tensor = forward();
1250 tensor.
assign(value, offset);
1258 return source_.compare(value, offset);
1262 Tensor tensor = forward();
1263 return tensor.
compare(value, offset);
1267template<
class Coordinates, Expression Source>
1270 Tensor complex(dtype(), shape(), strides(), offset(), real.buffer_);
1274template<
class Coordinates, Expression Real, Expression Imaginary>
1276 Tensor result(dtype(), shape(), strides(), offset());
1277 Coordinates::forward(real.forward(), imaginary.forward(), result);
1281template<Expression Source>
1284 Tensor real(dtype(), shape(), strides(), offset(),
complex.buffer_);
Memory buffer management for tensor storage.
A simple generic exception type for the Tannic Tensor Library.
Definition: exceptions.hpp:44
Host memory domain.
Definition: resources.hpp:60
Represents the shape (dimensions) of an tensor-like expression.
Definition: shape.hpp:79
constexpr rank_type rank() const noexcept
Returns the number of dimensions (rank).
Definition: shape.hpp:207
constexpr auto begin()
Definition: shape.hpp:215
size_t size_type
Type used for size and shape dimensions.
Definition: shape.hpp:85
constexpr auto end()
Definition: shape.hpp:219
Represents the memory strides associated with a tensor shape.
Definition: strides.hpp:87
A multidimensional, strided tensor data structure.
Definition: tensor.hpp:99
auto operator[](Indexes... indexes) const
Indexes the tensor with multiple indices (e.g., integers or ranges).
Definition: tensor.hpp:985
std::byte * bytes() const
Returns a pointer to the beginning of the tensor's data (accounting for offset).
Definition: tensor.hpp:247
void initialize(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< T > > > > values, Environment environment=Host{})
Assigns values to a 4D tensor from a quadruple-nested initializer list.
Definition: tensor.hpp:831
Environment const & environment() const
Returns a reference to the environment variant used to allocate this tensor's buffer.
Definition: tensor.hpp:264
Tensor & forward()
Returns a reference to this tensor (const-qualified).
Definition: tensor.hpp:218
auto transpose(int first=-1, int second=-2) const
Returns a view of the tensor with two dimensions transposed.
Definition: tensor.hpp:999
Tensor(std::initializer_list< std::initializer_list< T > > const &values)
Constructs a 2D tensor from a nested initializer list.
Definition: tensor.hpp:332
void initialize(Environment environment=Host{}) const
Allocates the memory buffer for the tensor.
Tensor(type dtype, Shape shape, Strides strides, std::ptrdiff_t offset=0)
Constructs an uninitialized tensor with custom strides and offset.
Definition: tensor.hpp:124
rank_type rank() const
Returns the number of dimensions (rank) of the tensor.
Definition: tensor.hpp:174
void initialize(std::initializer_list< T > values, Environment environment=Host{})
Assigns values to a 1D tensor from an initializer list.
Definition: tensor.hpp:558
std::size_t nbytes() const
Returns the total number of bytes occupied by the tensor's elements.
Definition: tensor.hpp:204
Tensor(std::initializer_list< std::initializer_list< std::initializer_list< T > > > const &values)
Constructs a 3D tensor from a triple-nested initializer list.
Definition: tensor.hpp:393
Tensor(type dtype, Shape shape)
Constructs an uninitialized tensor with default (contiguous) strides.
Definition: tensor.hpp:109
Node * node() const
Definition: tensor.hpp:1140
auto operator[](indexing::Range range) const
Indexes the tensor with a Range object.
Definition: tensor.hpp:961
auto squeeze() const
Returns a view of the tensor with all dimensions of size 1 removed.
Definition: tensor.hpp:1043
bool is_singleton() const
Definition: tensor.hpp:213
Shape::size_type size(int dimension) const
Returns the tensor's size at a given dimension.
Definition: tensor.hpp:184
bool is_initialized() const
Checks whether the tensor has been initialized with memory.
Definition: tensor.hpp:255
std::ptrdiff_t offset() const
Returns the offset of the tensor in the current buffer.
Definition: tensor.hpp:194
std::size_t size_type
Type used for size and shape dimensions.
Definition: tensor.hpp:102
Shape const & shape() const
Returns the tensor's shape (dimension sizes per dimension).
Definition: tensor.hpp:179
Tensor(std::initializer_list< std::initializer_list< std::initializer_list< std::initializer_list< T > > > > const &values)
Constructs a 4D tensor from a quadruple-nested initializer list.
Definition: tensor.hpp:474
Strides const & strides() const
Returns the tensor's strides (step sizes per dimension).
Definition: tensor.hpp:189
Tensor & operator=(const Expression &expression)
Assigns the result of an expression to the tensor.
Definition: tensor.hpp:159
bool is_contiguous() const
Returns whether the tensor's elements are in contiguous layout or not.
Definition: tensor.hpp:209
uint8_t rank_type
Type used for rank (number of dimensions).
Definition: tensor.hpp:101
auto permute(Indexes... indexes) const
Returns a view of the tensor with dimensions permuted.
Definition: tensor.hpp:1012
auto unsqueeze(Axes... axes)
Returns a view of the tensor with a dimension of size 1 inserted at the given axis.
Definition: tensor.hpp:1065
Tensor(type dtype, Shape shape, Strides strides, std::ptrdiff_t offset, std::shared_ptr< Buffer > storage)
Definition: tensor.hpp:1083
Tensor(const Expression &expression)
Constructs a tensor by forwarding an Expression-like object.
Definition: tensor.hpp:148
auto view(Sizes... sizes) const
Returns a view of the tensor with given sizes.
Definition: tensor.hpp:1025
Tensor(std::initializer_list< T > const &values)
@
Definition: tensor.hpp:288
void initialize(std::initializer_list< std::initializer_list< std::initializer_list< T > > > const &values, Environment environment=Host{})
Assigns values to a 3D tensor from a triple-nested initializer list.
Definition: tensor.hpp:723
auto operator[](Index index) const
Indexes the tensor with a single integral index.
Definition: tensor.hpp:941
Tensor(type dtype, Shape shape, std::ptrdiff_t offset, std::shared_ptr< Buffer > storage)
Definition: tensor.hpp:1072
void assign(std::byte const *, std::ptrdiff_t)
type dtype() const
Returns the tensor's data type.
Definition: tensor.hpp:169
bool compare(std::byte const *, std::ptrdiff_t) const
std::size_t nelements() const
Returns the total number of elements of the tensor.
Definition: tensor.hpp:199
void initialize(std::initializer_list< std::initializer_list< T > > const &values, Environment environment=Host{})
Assigns values to a 2D tensor from a nested initializer list.
Definition: tensor.hpp:633
Tensor const & forward() const
Returns a reference to this tensor (non-const).
Definition: tensor.hpp:225
void assign(bool const *, std::ptrdiff_t)
Creates a complex tensor view from real components.
Definition: complex.hpp:86
Expression template for expanding (broadcasting) singleton dimensions of a tensor.
Definition: views.hpp:398
Tensor forward() const
Definition: tensor.hpp:1219
Expression template for flattening a contiguous range of dimensions.
Definition: views.hpp:732
Tensor forward() const
Definition: tensor.hpp:1201
Expression template for reordering tensor dimensions according to a specified permutation.
Definition: views.hpp:303
Tensor forward() const
Definition: tensor.hpp:1207
Creates a real-valued view of complex tensor data.
Definition: complex.hpp:290
Tensor forward() const
Definition: tensor.hpp:1282
Expression template representing a tensor slice or subview.
Definition: slices.hpp:87
Tensor forward() const
Definition: tensor.hpp:1225
bool compare(std::byte const *value, std::ptrdiff_t offset) const
Definition: tensor.hpp:1256
void assign(std::byte const *value, std::ptrdiff_t offset)
Definition: tensor.hpp:1231
Expression template for removing singleton dimensions from a tensor.
Definition: views.hpp:523
Tensor forward() const
Definition: tensor.hpp:1189
Expression template for transposing two dimensions of a tensor.
Definition: views.hpp:211
Tensor forward() const
Definition: tensor.hpp:1213
Expression template for inserting singleton dimensions into a tensor.
Definition: views.hpp:619
Tensor forward() const
Definition: tensor.hpp:1195
Expression template for viewing a tensor with a new shape.
Definition: views.hpp:84
Tensor forward() const
Definition: tensor.hpp:1183
Tensor forward() const
Definition: tensor.hpp:1176
Tensor forward() const
Evaluates the unary expression and returns a Tensor.
Definition: tensor.hpp:1169
Complex number operations for the Tannic Tensor Library.
Defines the core protocol for all expression-like types in the Tannic Tensor Library.
Definition: concepts.hpp:85
Requires a type to be an integral type (e.g., int, std::size_t).
Definition: concepts.hpp:146
std::byte const * tobytes(T const &reference)
Definition: slices.hpp:343
constexpr auto complex(Real &&real, Imaginary &&imaginary)
Creates complex tensor from separate real and imaginary tensors
Definition: complex.hpp:426
Definition: buffer.hpp:41
constexpr type dtypeof()
Definition: types.hpp:229
std::ostream & operator<<(std::ostream &os, Shape const &shape)
Definition: shape.hpp:313
constexpr std::size_t nbytesof(type dtype, std::size_t nelements)
Returns the total number of bytes required to store nelements elements of the given data type.
Definition: types.hpp:129
std::variant< Host, Device > Environment
Memory environment variant type.
Definition: resources.hpp:204
constexpr std::size_t dsizeof(type type)
Returns the size in bytes of a given tensor data type.
Definition: types.hpp:94
Defines expression templates tensor aritmetic operations.
Defines the tannic::Shape class for representing tensor dimensions.
Implements tensor slicing for expression templates in the Tannic Tensor Library.
Memory layout specification for tensor dimensions in the Tannic Tensor Library.
Definition: traits.hpp:27
Represents a half-open interval [start, stop) for slicing.
Definition: indexing.hpp:56
Core type system for the Tannic Tensor Library.
Implements views for tensors in the Tannic Tensor Library.