batmat 0.0.15
Batched linear algebra routines
Loading...
Searching...
No Matches
view.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file
4/// Non-owning view of a batch of matrices.
5/// @ingroup topic-matrix
6
7#include <batmat/assume.hpp>
8#include <batmat/config.hpp>
10#include <guanaqo/mat-view.hpp>
11#include <type_traits>
12
13namespace batmat::matrix {
14
15/// Non-owning view of a batch of matrices.
16/// @tparam T
17/// Element value type (possibly const-qualified).
18/// @tparam I
19/// Index and size type. Usually `std::ptrdiff_t` or `int`.
20/// @tparam S
21/// Inner stride type (batch size). Usually `std::integral_constant<I, N>` for some `N`.
22/// @tparam D
23/// Batch depth type. Usually equal to @p S for a single batch, or @p I for a dynamic depth.
24/// @tparam L
25/// Layer stride type. Usually @ref DefaultStride (which implies that the layer stride is
26/// equal to `outer_stride() * outer_size()`), or @p I for a dynamic layer stride.
27/// Dynamic strides are used for subviews of views with a larger `outer_size()`.
28/// @tparam O
29/// Storage order (column or row major).
30/// @ingroup topic-matrix
31template <class T, class I = index_t, class S = std::integral_constant<I, 1>, class D = I,
32 class L = DefaultStride, StorageOrder O = StorageOrder::ColMajor>
33struct View {
35 using value_type = T;
44 static constexpr bool is_row_major = layout_type::is_row_major;
45
46 /// True if @ref batch_size() and @ref depth() are compile-time constants and are equal.
47 /// @note Views with dynamic batch size and depth may still have a single batch at runtime,
48 /// but this cannot be statically asserted.
49 static constexpr bool has_single_batch_at_compile_time = requires {
50 S::value;
51 D::value;
52 } && S{} == D{};
53 /// True if @ref depth() is a compile-time constant and is equal to one.
54 static constexpr bool has_single_layer_at_compile_time = requires { D::value; } && D{} == 1;
55 /// When extracing a single batch, the depth equals the batch size, and the layer stride is no
56 /// longer relevant.
58 /// When slicing along the outer dimension, the layer stride stays the same, but the outer size
59 /// may be smaller, which means that even if the original view has a default layer stride, the
60 /// sliced view may require a dynamic layer stride. For a single batch, the layer stride is not
61 /// relevant, so it is preserved.
63 std::conditional_t<has_single_batch_at_compile_time, View, View<T, I, S, D, I, O>>;
64 /// View with the correct layer stride when slicing along the column dimension.
65 /// For row-major storage, slicing along columns does not change the outer size, in which case
66 /// the layer stride is still correct. For column-major storage, slicing along columns does
67 /// change the outer size, in which case we need a dynamic layer stride.
68 using col_slice_view_type = std::conditional_t<is_row_major, View, general_slice_view_type>;
69 /// View with the correct layer stride when slicing along the row dimension.
70 /// @see @ref col_slice_view_type
71 using row_slice_view_type = std::conditional_t<is_column_major, View, general_slice_view_type>;
72
73 /// Pointer to the first element of the first layer.
75 /// Layout describing the dimensions and strides of the view.
77
78 /// @name Constructors
79 /// @{
80
81 /// POD helper struct to enable designated initializers during construction.
93
94 /// Create a new view.
95 /// @note It is recommended to use designated initializers for the arguments to avoid mistakes.
96 constexpr View(PlainBatchedMatrixView p = {})
97 : data_ptr{p.data}, layout{{.depth = p.depth,
98 .rows = p.rows,
99 .cols = p.cols,
100 .outer_stride = p.outer_stride,
101 .batch_size = p.batch_size,
102 .layer_stride = p.layer_stride}} {}
103 /// Create a new view with the given layout, using the given buffer.
104 constexpr View(std::span<T> data, layout_type layout) : data_ptr{data.data()}, layout{layout} {
105 BATMAT_ASSERT(data.size() == layout.padded_size());
106 }
107 /// Create a new view with the given layout, using the given buffer.
109
110 /// Copy a view. No data is copied.
111 View(const View &) = default;
112
113 /// Reassign the buffer and layout of this view to those of another view. No data is copied.
115 this->data_ptr = other.data_ptr;
116 this->layout = other.layout;
117 return *this;
118 }
119
120 /// @}
121
122 /// @name Element access
123 /// @{
124
125 /// Access a single element at layer @p l, row @p r and column @p c.
126 [[nodiscard]] value_type &operator()(index_type l, index_type r, index_type c) const {
127 return layout(data_ptr, l, r, c);
128 }
129
130 /// @}
131
132 /// @name Batch-wise slicing
133 /// @{
134
135 /// Access a batch of @ref batch_size() layers, starting at batch index @p b (i.e. starting at
136 /// layer `b * batch_size()`).
137 [[nodiscard]] batch_view_type batch(index_type b) const {
138 const auto layer = b * static_cast<index_t>(batch_size());
139 return {{.data = data() + layout.layer_index(layer),
140 .depth = batch_size(),
141 .rows = rows(),
142 .cols = cols(),
143 .outer_stride = outer_stride(),
144 .batch_size = batch_size()}};
145 }
146
147 /// Same as @ref batch(), but returns a view with a dynamic batch size. If the total depth is
148 /// not a multiple of the batch size, the last batch will have a smaller size.
150 const auto d = static_cast<I>(depth());
151 const auto layer = b * static_cast<index_t>(batch_size());
152 const auto last = b == d / batch_size();
153 return {{.data = data() + layout.layer_index(layer),
154 .depth = last ? d - layout.floor_depth() : batch_size(),
155 .rows = rows(),
156 .cols = cols(),
157 .outer_stride = outer_stride(),
158 .batch_size = batch_size(),
159 .layer_stride = layout.layer_stride}};
160 }
161
162 /// Get a view of @p n batches starting at batch @p b, with a stride of @p stride layers.
164 index_type stride = 1) const {
165 const auto bs = static_cast<I>(batch_size());
166 const auto layer = b * bs;
167 BATMAT_ASSERT(n == 0 || layer + (n - 1) * stride * bs + bs <= depth());
168 return {{.data = data() + layout.layer_index(layer),
169 .depth = n,
170 .rows = rows(),
171 .cols = cols(),
172 .outer_stride = outer_stride(),
173 .batch_size = batch_size(),
174 .layer_stride = layout.get_layer_stride() * stride}};
175 }
176
177 /// @}
178
179 /// @name Layer-wise slicing
180 /// @{
181
182 /// Access a single layer @p l as a non-batched view.
183 /// @note The inner stride of the returned view is equal to the batch size of this view, so it
184 /// cannot be used directly with functions that require unit inner stride (e.g. BLAS).
187 return layout(data_ptr, l);
188 }
189
190 /// Get a view of the first @p n layers. Note that @p n can be a compile-time constant.
191 template <class N>
192 [[nodiscard]] View<T, I, S, N, L, O> first_layers(N n) const {
193 BATMAT_ASSERT(n <= depth());
194 return {{.data = data(),
195 .depth = n,
196 .rows = rows(),
197 .cols = cols(),
198 .outer_stride = outer_stride(),
199 .batch_size = batch_size(),
200 .layer_stride = layout.layer_stride}};
201 }
202
203 /// Get a view of @p n layers starting at layer @p l. Note that @p n can be a compile-time
204 /// constant.
205 /// @pre `l % batch_size() == 0` (i.e. the starting layer must be at the start of a batch).
206 template <class N>
207 [[nodiscard]] View<T, I, S, N, L, O> middle_layers(index_type l, N n) const {
208 BATMAT_ASSERT(l + n <= depth());
209 BATMAT_ASSERT(l % static_cast<I>(batch_size()) == 0);
210 return {{.data = data() + layout.layer_index(l),
211 .depth = n,
212 .rows = rows(),
213 .cols = cols(),
214 .outer_stride = outer_stride(),
215 .batch_size = batch_size(),
216 .layer_stride = layout.layer_stride}};
217 }
218
219 /// @}
220
221 /// @name Iterators and buffer access
222 /// @{
223
224 /// Get a pointer to the first element of the first layer.
225 T *data() const { return data_ptr; }
226
227 /// Iterator over all elements of a view.
229 using value_type = T;
230 using reference = T &;
233 T *end;
237
239 ++data;
240 if (data == next_jump && data != end) {
243 }
244 return *this;
245 }
247 linear_iterator t = *this;
248 ++*this;
249 return t;
250 }
251 reference operator*() const { return *data; }
252 bool operator==(std::default_sentinel_t) const { return data == end; }
253 };
254
255 /// Iterate linearly (in storage order) over all elements of the view.
256 /// @pre `has_full_outer_stride()` (i.e. no padding within layers).
257 /// @pre `has_full_layer_stride()` (i.e. no padding between batches).
258 [[nodiscard]] linear_iterator begin() const {
261 // Number of elements in each layer
262 const auto size = layout.rows * layout.cols;
263 // How many layers are in batches that are completely full?
264 const auto contig_layers = layout.floor_depth();
265 // How many layers in total?
266 const auto depth = static_cast<I>(layout.depth);
267 // Remaining layers have padding we should skip over (in the last batch)
268 const auto remaining_layers = depth - contig_layers;
269 // Index of the first padding element
270 const auto first_jump = contig_layers * size + remaining_layers;
271 // Index of last layer in our storage
272 const auto padded_end = layout.ceil_depth();
273 const auto padding_layers = padded_end - depth;
274 const auto end = padded_end * size - padding_layers;
275 const auto batch_size = static_cast<I>(layout.batch_size);
276 return {
277 .data = data(),
278 .end = data() + end,
279 .next_jump = remaining_layers ? data() + first_jump : nullptr,
280 .padding_size = batch_size - remaining_layers,
281 .batch_size = batch_size,
282 };
283 }
284 /// Sentinel for @ref begin().
285 [[nodiscard]] std::default_sentinel_t end() const { return {}; }
286
287 /// @}
288
289 /// @name Dimensions
290 /// @{
291
292 /// Total number of elements in the view (excluding padding).
293 [[nodiscard]] constexpr index_type size() const { return layout.size(); }
294 /// Total number of elements in the view (including all padding).
295 [[nodiscard]] constexpr index_type padded_size() const { return layout.padded_size(); }
296
297 /// Number of layers in the view (i.e. depth).
298 [[nodiscard, gnu::always_inline]] constexpr depth_type depth() const { return layout.depth; }
299 /// The depth rounded up to a multiple of the batch size.
300 [[nodiscard, gnu::always_inline]] constexpr index_type ceil_depth() const {
301 return layout.ceil_depth();
302 }
303 /// The batch size, i.e. the number of layers in each batch. Equals the inner stride.
304 [[nodiscard, gnu::always_inline]] constexpr batch_size_type batch_size() const {
305 return layout.batch_size;
306 }
307 /// Number of batches in the view, i.e. `ceil_depth() / batch_size()`.
308 [[nodiscard, gnu::always_inline]] constexpr index_type num_batches() const {
309 return layout.num_batches();
310 }
311 /// Number of rows of the matrices.
312 [[nodiscard, gnu::always_inline]] constexpr index_type rows() const { return layout.rows; }
313 /// Number of columns of the matrices.
314 [[nodiscard, gnu::always_inline]] constexpr index_type cols() const { return layout.cols; }
315 /// The size of the outer dimension, i.e. the number of columns for column-major storage, or the
316 /// number of rows for row-major storage.
317 [[nodiscard, gnu::always_inline]] constexpr index_type outer_size() const {
318 return layout.outer_size();
319 }
320 /// The size of the inner dimension, i.e. the number of rows for column-major storage, or the
321 /// number of columns for row-major storage.
322 [[nodiscard, gnu::always_inline]] constexpr index_type inner_size() const {
323 return layout.inner_size();
324 }
325
326 /// @}
327
328 /// @name Strides
329 /// @{
330
331 /// Outer stride of the matrices (leading dimension in BLAS parlance). Should be multiplied by
332 /// the batch size to get the actual number of elements.
333 [[nodiscard, gnu::always_inline]] constexpr index_type outer_stride() const {
334 return layout.outer_stride;
335 }
336 /// The inner stride of the matrices. Should be multiplied by the batch size to get the actual
337 /// number of elements.
338 [[nodiscard, gnu::always_inline]] constexpr auto inner_stride() const {
339 return layout.inner_stride;
340 }
341 /// The row stride of the matrices, i.e. the distance between elements in consecutive rows in
342 /// a given column. Should be multiplied by the batch size to get the actual number of elements.
343 [[nodiscard, gnu::always_inline]] constexpr auto row_stride() const {
344 return layout.row_stride();
345 }
346 /// The column stride of the matrices, i.e. the distance between elements in consecutive columns
347 /// in a given row. Should be multiplied by the batch size to get the actual number of elements.
348 [[nodiscard, gnu::always_inline]] constexpr auto col_stride() const {
349 return layout.col_stride();
350 }
351 /// The layer stride, i.e. the distance between the first layer of one batch and the first layer
352 /// of the next batch. Should be multiplied by the batch size to get the actual number of
353 /// elements.
354 [[nodiscard, gnu::always_inline]] constexpr index_type layer_stride() const {
355 return layout.get_layer_stride();
356 }
357 /// Whether the `layer_stride() == outer_stride() * outer_size()`.
358 [[nodiscard, gnu::always_inline]] constexpr bool has_full_layer_stride() const {
359 return layout.has_full_layer_stride();
360 }
361 /// Whether the `outer_stride() == inner_stride() * inner_size()`.
362 [[nodiscard, gnu::always_inline]] constexpr bool has_full_outer_stride() const {
363 return layout.has_full_outer_stride();
364 }
365 /// Whether the `inner_stride() == 1`. Always true.
366 [[nodiscard, gnu::always_inline]] constexpr bool has_full_inner_stride() const {
367 return layout.has_full_inner_stride();
368 }
369
370 /// @}
371
372 private:
373 template <class V>
374 constexpr auto get_layer_stride_for() const {
375 if constexpr (std::is_same_v<typename V::layer_stride_type, layer_stride_type>)
376 return layout.layer_stride;
377 else
378 return layer_stride();
379 }
380
381 public:
382 /// @name Reshaping and slicing
383 /// @{
384
385 /// Reshape the view to the given dimensions. The total size should not change.
387 BATMAT_ASSERT(rows * cols == this->rows() * this->cols());
389 return general_slice_view_type{typename general_slice_view_type::PlainBatchedMatrixView{
390 .data = data(),
391 .depth = depth(),
392 .rows = rows,
393 .cols = cols,
394 .outer_stride = is_row_major ? cols : rows,
395 .batch_size = batch_size(),
396 .layer_stride = this->get_layer_stride_for<general_slice_view_type>()}};
397 }
398
399 /// Get a view of the first @p n rows.
400 [[nodiscard]] row_slice_view_type top_rows(index_type n) const {
401 BATMAT_ASSERT(0 <= n && n <= rows());
402 return row_slice_view_type{typename row_slice_view_type::PlainBatchedMatrixView{
403 .data = data(),
404 .depth = depth(),
405 .rows = n,
406 .cols = cols(),
407 .outer_stride = outer_stride(),
408 .batch_size = batch_size(),
409 .layer_stride = this->get_layer_stride_for<row_slice_view_type>()}};
410 }
411
412 /// Get a view of the first @p n columns.
413 [[nodiscard]] col_slice_view_type left_cols(index_type n) const {
414 BATMAT_ASSERT(0 <= n && n <= cols());
415 return col_slice_view_type{typename col_slice_view_type::PlainBatchedMatrixView{
416 .data = data(),
417 .depth = depth(),
418 .rows = rows(),
419 .cols = n,
420 .outer_stride = outer_stride(),
421 .batch_size = batch_size(),
422 .layer_stride = this->get_layer_stride_for<col_slice_view_type>()}};
423 }
424
425 /// Get a view of the last @p n rows.
427 BATMAT_ASSERT(0 <= n && n <= rows());
428 const auto bs = static_cast<I>(batch_size());
429 const auto offset = (is_row_major ? outer_stride() : 1) * bs * (rows() - n);
430 return row_slice_view_type{typename row_slice_view_type::PlainBatchedMatrixView{
431 .data = data() + offset,
432 .depth = depth(),
433 .rows = n,
434 .cols = cols(),
435 .outer_stride = outer_stride(),
436 .batch_size = batch_size(),
437 .layer_stride = this->get_layer_stride_for<row_slice_view_type>()}};
438 }
439
440 /// Get a view of the last @p n columns.
442 BATMAT_ASSERT(0 <= n && n <= cols());
443 const auto bs = static_cast<I>(batch_size());
444 const auto offset = (is_row_major ? 1 : outer_stride()) * bs * (cols() - n);
445 return col_slice_view_type{typename col_slice_view_type::PlainBatchedMatrixView{
446 .data = data() + offset,
447 .depth = depth(),
448 .rows = rows(),
449 .cols = n,
450 .outer_stride = outer_stride(),
451 .batch_size = batch_size(),
452 .layer_stride = this->get_layer_stride_for<col_slice_view_type>()}};
453 }
454
455 /// Get a view of @p n rows starting at row @p r.
457 return bottom_rows(rows() - r).top_rows(n);
458 }
459
460 /// Get a view of @p n rows starting at row @p r, with stride @p stride.
462 index_type stride) const
463 requires is_row_major
464 {
465 BATMAT_ASSERT(0 <= r);
466 BATMAT_ASSERT(r + (n - 1) * stride < rows());
467 const auto bs = static_cast<I>(batch_size());
468 const auto offset = outer_stride() * bs * r;
469 return row_slice_view_type{typename row_slice_view_type::PlainBatchedMatrixView{
470 .data = data() + offset,
471 .depth = depth(),
472 .rows = n,
473 .cols = cols(),
474 .outer_stride = outer_stride() * stride,
475 .batch_size = batch_size(),
476 .layer_stride = this->get_layer_stride_for<row_slice_view_type>()}};
477 }
478
479 /// Get a view of @p n columns starting at column @p c.
481 return right_cols(cols() - c).left_cols(n);
482 }
483
484 /// Get a view of @p n columns starting at column @p c, with stride @p stride.
486 index_type stride) const
487 requires is_column_major
488 {
489 BATMAT_ASSERT(0 <= c);
490 BATMAT_ASSERT(c + (n - 1) * stride < cols());
491 const auto bs = static_cast<I>(batch_size());
492 const auto offset = outer_stride() * bs * c;
493 return col_slice_view_type{typename col_slice_view_type::PlainBatchedMatrixView{
494 .data = data() + offset,
495 .depth = depth(),
496 .rows = rows(),
497 .cols = n,
498 .outer_stride = outer_stride() * stride,
499 .batch_size = batch_size(),
500 .layer_stride = this->get_layer_stride_for<col_slice_view_type>()}};
501 }
502
503 /// Get a view of the top-left @p nr by @p nc block of the matrices.
505 return top_rows(nr).left_cols(nc);
506 }
507
508 /// Get a view of the top-right @p nr by @p nc block of the matrices.
510 return top_rows(nr).right_cols(nc);
511 }
512
513 /// Get a view of the bottom-left @p nr by @p nc block of the matrices.
515 return bottom_rows(nr).left_cols(nc);
516 }
517
518 /// Get a view of the bottom-right @p nr by @p nc block of the matrices.
520 return bottom_rows(nr).right_cols(nc);
521 }
522
523 /// Get a view of the @p nr by @p nc block of the matrices starting at row @p r and column @p c.
525 index_type nc) const {
526 return middle_rows(r, nr).middle_cols(c, nc);
527 }
528
529 /// Get a view of the given span as a column vector.
530 [[nodiscard]] static View as_column(std::span<T> v) {
531 return {{.data = v.data(), .rows = static_cast<index_type>(v.size()), .cols = 1}};
532 }
533
534 /// Get a transposed view of the matrices. Note that the data itself is not modified, the
535 /// returned view simply accesses the same data with rows and column indices swapped.
536 [[nodiscard]] auto transposed() const {
537 using TpBm = View<T, I, S, D, L, transpose(O)>;
538 return TpBm{typename TpBm::PlainBatchedMatrixView{.data = data(),
539 .depth = depth(),
540 .rows = cols(),
541 .cols = rows(),
542 .outer_stride = outer_stride(),
543 .batch_size = batch_size(),
544 .layer_stride = layout.layer_stride}};
545 }
546
547 /// @}
548
549 /// @name Value manipulation
550 /// @{
551
553 const auto bs = static_cast<I>(batch_size());
554 const auto n = std::min(rows(), cols());
555 for (index_type b = 0; b < num_batches(); ++b) {
556 auto *p = batch(b).data();
557 for (index_type i = 0; i < n; ++i) {
558 for (index_type r = 0; r < bs; ++r)
559 *p++ += t;
560 p += bs * outer_stride();
561 }
562 }
563 }
564
566 const auto bs = static_cast<I>(batch_size());
567 for (index_type b = 0; b < num_batches(); ++b) {
568 auto *dst = this->batch(b).data();
569 for (index_type c = 0; c < this->outer_size(); ++c) {
570 auto *dst_ = dst;
571 const index_type n = inner_size() * bs;
572 for (index_type r = 0; r < n; ++r)
573 *dst_++ = t;
574 dst += bs * this->outer_stride();
575 }
576 }
577 }
578
579 void negate() {
580 const auto bs = static_cast<I>(batch_size());
581 for (index_type b = 0; b < num_batches(); ++b) {
582 auto *dst = this->batch(b).data();
583 for (index_type c = 0; c < this->outer_size(); ++c) {
584 auto *dst_ = dst;
585 const index_type n = inner_size() * bs;
586 for (index_type r = 0; r < n; ++r, ++dst_)
587 *dst_ = -*dst_;
588 dst += bs * this->outer_stride();
589 }
590 }
591 }
592
593 template <class Other>
594 void copy_values(const Other &other) const {
595 static_assert(is_row_major == Other::is_row_major);
596 assert(other.rows() == this->rows());
597 assert(other.cols() == this->cols());
598 assert(other.batch_size() == this->batch_size());
599 const auto bs = static_cast<I>(batch_size());
600 for (index_type b = 0; b < num_batches(); ++b) {
601 const auto *src = other.batch(b).data();
602 auto *dst = this->batch(b).data();
603 for (index_type c = 0; c < this->outer_size(); ++c) {
604 const auto *src_ = src;
605 auto *dst_ = dst;
606 const index_type n = inner_size() * bs;
607 for (index_type r = 0; r < n; ++r)
608 *dst_++ = *src_++;
609 src += bs * other.outer_stride();
610 dst += bs * this->outer_stride();
611 }
612 }
613 }
614
615 /// Copy assignment copies the values from another view with the same layout to this view.
616 View &operator=(const View &other) {
617 if (this != &other)
618 copy_values(other);
619 return *this;
620 }
621 /// Copy values from another view with a compatible value type and the same layout to this view.
622 template <class U, class J, class R, class E, class M>
623 requires(!std::is_const_v<T> && std::convertible_to<U, std::remove_cv_t<T>> &&
624 std::equality_comparable_with<I, J>)
625 View &operator=(View<U, J, R, E, M, O> other) {
626 copy_values(other);
627 return *this;
628 }
629 // TODO: abstract logic into generic function (and check performance)
630 template <class U, class J, class R, class E, class M>
631 requires(!std::is_const_v<T> && std::convertible_to<U, std::remove_cv_t<T>> &&
632 std::equality_comparable_with<I, J>)
633 View &operator+=(View<U, J, R, E, M, O> other) {
634 assert(other.rows() == this->rows());
635 assert(other.cols() == this->cols());
636 assert(other.batch_size() == this->batch_size());
637 const auto bs = static_cast<I>(batch_size());
638 for (index_type b = 0; b < num_batches(); ++b) {
639 const auto *src = other.batch(b).data();
640 auto *dst = this->batch(b).data();
641 for (index_type c = 0; c < this->outer_size(); ++c) {
642 const auto *src_ = src;
643 auto *dst_ = dst;
644 const index_type n = inner_size() * bs;
645 for (index_type r = 0; r < n; ++r)
646 *dst_++ += *src_++;
647 src += bs * other.outer_stride();
648 dst += bs * this->outer_stride();
649 }
650 }
651 return *this;
652 }
653
654 /// @}
655
656 /// @name View conversions
657 /// @{
658
659 /// Returns the same view. For consistency with @ref Matrix.
660 [[nodiscard]] View view() const { return *this; }
661 /// Explicit conversion to a const view.
662 [[nodiscard]] const_view_type as_const() const { return *this; }
663
664 /// Non-const views implicitly convert to const views.
665 operator const_view_type() const
666 requires(!std::is_const_v<T>)
667 {
668 return {data_ptr, layout};
669 }
670
671 /// If we have a single layer at compile time, we can implicitly convert to a non-batched view.
677
678 /// Implicit conversion to a view with a dynamic depth.
680 requires(!std::same_as<integral_value_type_t<D>, D>)
681 {
682 const auto bs = static_cast<integral_value_type_t<D>>(batch_size());
683 return {{.data = data(),
684 .depth = depth(),
685 .rows = rows(),
686 .cols = cols(),
687 .outer_stride = outer_stride(),
688 .batch_size = bs,
689 .layer_stride = layout.layer_stride}};
690 }
691 /// Implicit conversion to a view with a dynamic depth, going from non-const to const.
693 requires(!std::is_const_v<T> && !std::same_as<integral_value_type_t<D>, D>)
694 {
695 const auto bs = static_cast<integral_value_type_t<D>>(batch_size());
696 return {{.data = data(),
697 .depth = depth(),
698 .rows = rows(),
699 .cols = cols(),
700 .outer_stride = outer_stride(),
701 .batch_size = bs,
702 .layer_stride = layout.layer_stride}};
703 }
704 /// Implicit conversion to a view with a dynamic layer stride.
705 operator View<T, I, S, D, I, O>() const
706 requires(!std::same_as<I, L>)
707 {
708 return {{.data = data(),
709 .depth = depth(),
710 .rows = rows(),
711 .cols = cols(),
712 .outer_stride = outer_stride(),
713 .batch_size = batch_size(),
714 .layer_stride = layer_stride()}};
715 }
716 /// Implicit conversion to a view with a dynamic layer stride, going from non-const to const.
718 requires(!std::is_const_v<T> && !std::same_as<I, L>)
719 {
720 return {{.data = data(),
721 .depth = depth(),
722 .rows = rows(),
723 .cols = cols(),
724 .outer_stride = outer_stride(),
725 .batch_size = batch_size(),
726 .layer_stride = layer_stride()}};
727 }
728
729 /// @}
730};
731
732template <class T, class I, class S, class D, class L, StorageOrder P>
733bool operator==(std::default_sentinel_t s, typename View<T, I, S, D, L, P>::linear_iterator i) {
734 return i == s;
735}
736template <class T, class I, class S, class D, class L, StorageOrder P>
737bool operator!=(std::default_sentinel_t s, typename View<T, I, S, D, L, P>::linear_iterator i) {
738 return !(i == s);
739}
740template <class T, class I, class S, class D, class L, StorageOrder P>
741bool operator!=(typename View<T, I, S, D, L, P>::linear_iterator i, std::default_sentinel_t s) {
742 return !(i == s);
743}
744
745// TODO: tag-invoke style CPOs instead of free functions with ADL?
746
747template <class T, class I, class S, class D, class L, StorageOrder O>
748constexpr auto data(const View<T, I, S, D, L, O> &v) {
749 return v.data();
750}
751template <class T, class I, class S, class D, class L, StorageOrder O>
752constexpr auto rows(const View<T, I, S, D, L, O> &v) {
753 return v.rows();
754}
755template <class T, class I, class S, class D, class L, StorageOrder O>
756constexpr auto cols(const View<T, I, S, D, L, O> &v) {
757 return v.cols();
758}
759template <class T, class I, class S, class D, class L, StorageOrder O>
760constexpr auto outer_stride(const View<T, I, S, D, L, O> &v) {
761 return v.outer_stride();
762}
763template <class T, class I, class S, class D, class L, StorageOrder O>
764constexpr auto depth(const View<T, I, S, D, L, O> &v) {
765 return v.depth();
766}
767
768} // namespace batmat::matrix
#define BATMAT_ASSERT(x)
Definition assume.hpp:14
Layout description for a batch of matrices, independent of any storage.
constexpr auto cols(const Matrix< T, I, S, D, O, A > &v)
Definition matrix.hpp:490
typename integral_value_type< T >::type integral_value_type_t
Definition layout.hpp:25
constexpr auto data(Matrix< T, I, S, D, O, A > &v)
Definition matrix.hpp:476
constexpr auto outer_stride(const Matrix< T, I, S, D, O, A > &v)
Definition matrix.hpp:494
bool operator!=(std::default_sentinel_t s, typename View< T, I, S, D, L, P >::linear_iterator i)
Definition view.hpp:737
constexpr auto rows(const Matrix< T, I, S, D, O, A > &v)
Definition matrix.hpp:486
bool operator==(std::default_sentinel_t s, typename View< T, I, S, D, L, P >::linear_iterator i)
Definition view.hpp:733
constexpr auto depth(const Matrix< T, I, S, D, O, A > &v)
Definition matrix.hpp:498
Shape and strides describing a batch of matrices, independent of any storage.
Definition layout.hpp:46
static constexpr bool is_column_major
Definition layout.hpp:54
static constexpr bool is_row_major
Definition layout.hpp:55
static constexpr StorageOrder storage_order
Definition layout.hpp:53
std::conditional_t< requires { S::value; }, std::integral_constant< index_t, S::value >, index_t > standard_stride_type
Definition layout.hpp:58
Iterator over all elements of a view.
Definition view.hpp:228
bool operator==(std::default_sentinel_t) const
Definition view.hpp:252
linear_iterator operator++(int)
Definition view.hpp:246
linear_iterator & operator++()
Definition view.hpp:238
Non-owning view of a batch of matrices.
Definition view.hpp:33
constexpr View(PlainBatchedMatrixView p={})
Create a new view.
Definition view.hpp:96
Layout< index_t, stride, stride, layer_stride, O > layout_type
Definition view.hpp:34
View< T, I, S, N, L, O > first_layers(N n) const
Get a view of the first n layers. Note that n can be a compile-time constant.
Definition view.hpp:192
typename layout_type::layer_stride_type layer_stride_type
Definition view.hpp:39
guanaqo::MatrixView< T, I, standard_stride_type, O > operator()(index_type l) const
Access a single layer l as a non-batched view.
Definition view.hpp:186
general_slice_view_type bottom_right(index_type nr, index_type nc) const
Get a view of the bottom-right nr by nc block of the matrices.
Definition view.hpp:519
typename layout_type::batch_size_type batch_size_type
Definition view.hpp:37
typename layout_type::standard_stride_type standard_stride_type
Definition view.hpp:40
View< T, index_t, stride, stride, DefaultStride, O > batch_view_type
Definition view.hpp:57
general_slice_view_type block(index_type r, index_type c, index_type nr, index_type nc) const
Get a view of the nr by nc block of the matrices starting at row r and column c.
Definition view.hpp:524
void set_constant(value_type t)
Definition view.hpp:565
value_type & operator()(index_type l, index_type r, index_type c) const
Access a single element at layer l, row r and column c.
Definition view.hpp:126
auto transposed() const
Get a transposed view of the matrices.
Definition view.hpp:536
constexpr auto inner_stride() const
The inner stride of the matrices.
Definition view.hpp:338
constexpr index_type num_batches() const
Number of batches in the view, i.e. ceil_depth() / batch_size().
Definition view.hpp:308
col_slice_view_type middle_cols(index_type c, index_type n, index_type stride) const
Get a view of n columns starting at column c, with stride stride.
Definition view.hpp:485
constexpr View(value_type *data, layout_type layout)
Create a new view with the given layout, using the given buffer.
Definition view.hpp:108
col_slice_view_type middle_cols(index_type c, index_type n) const
Get a view of n columns starting at column c.
Definition view.hpp:480
constexpr index_type padded_size() const
Total number of elements in the view (including all padding).
Definition view.hpp:295
void add_to_diagonal(const value_type &t)
Definition view.hpp:552
linear_iterator begin() const
Iterate linearly (in storage order) over all elements of the view.
Definition view.hpp:258
constexpr auto get_layer_stride_for() const
Definition view.hpp:374
row_slice_view_type bottom_rows(index_type n) const
Get a view of the last n rows.
Definition view.hpp:426
general_slice_view_type reshaped(index_type rows, index_type cols) const
Reshape the view to the given dimensions. The total size should not change.
Definition view.hpp:386
View< T, I, S, N, L, O > middle_layers(index_type l, N n) const
Get a view of n layers starting at layer l.
Definition view.hpp:207
View(const View &)=default
Copy a view. No data is copied.
constexpr auto col_stride() const
The column stride of the matrices, i.e.
Definition view.hpp:348
general_slice_view_type bottom_left(index_type nr, index_type nc) const
Get a view of the bottom-left nr by nc block of the matrices.
Definition view.hpp:514
View< const T, index_t, stride, stride, layer_stride, O > const_view_type
Definition view.hpp:41
row_slice_view_type middle_rows(index_type r, index_type n) const
Get a view of n rows starting at row r.
Definition view.hpp:456
constexpr index_type cols() const
Number of columns of the matrices.
Definition view.hpp:314
col_slice_view_type right_cols(index_type n) const
Get a view of the last n columns.
Definition view.hpp:441
View< T, I, S, I, L, O > batch_dyn(index_type b) const
Same as batch(), but returns a view with a dynamic batch size.
Definition view.hpp:149
constexpr bool has_full_inner_stride() const
Whether the inner_stride() == 1. Always true.
Definition view.hpp:366
col_slice_view_type left_cols(index_type n) const
Get a view of the first n columns.
Definition view.hpp:413
static View as_column(std::span< T > v)
Get a view of the given span as a column vector.
Definition view.hpp:530
row_slice_view_type top_rows(index_type n) const
Get a view of the first n rows.
Definition view.hpp:400
constexpr index_type rows() const
Number of rows of the matrices.
Definition view.hpp:312
constexpr index_type inner_size() const
The size of the inner dimension, i.e.
Definition view.hpp:322
constexpr index_type ceil_depth() const
The depth rounded up to a multiple of the batch size.
Definition view.hpp:300
View & operator=(const View &other)
Copy assignment copies the values from another view with the same layout to this view.
Definition view.hpp:616
std::conditional_t< has_single_batch_at_compile_time, View, View< T, index_t, stride, stride, index_t, O > > general_slice_view_type
Definition view.hpp:62
constexpr auto row_stride() const
The row stride of the matrices, i.e.
Definition view.hpp:343
std::conditional_t< is_column_major, View, general_slice_view_type > row_slice_view_type
Definition view.hpp:71
row_slice_view_type middle_rows(index_type r, index_type n, index_type stride) const
Get a view of n rows starting at row r, with stride stride.
Definition view.hpp:461
constexpr View(std::span< T > data, layout_type layout)
Create a new view with the given layout, using the given buffer.
Definition view.hpp:104
general_slice_view_type top_left(index_type nr, index_type nc) const
Get a view of the top-left nr by nc block of the matrices.
Definition view.hpp:504
constexpr index_type outer_size() const
The size of the outer dimension, i.e.
Definition view.hpp:317
View view() const
Returns the same view. For consistency with Matrix.
Definition view.hpp:660
constexpr index_type layer_stride() const
The layer stride, i.e.
Definition view.hpp:354
View< T, I, S, I, I, O > middle_batches(index_type b, index_type n, index_type stride=1) const
Get a view of n batches starting at batch b, with a stride of stride layers.
Definition view.hpp:163
const_view_type as_const() const
Explicit conversion to a const view.
Definition view.hpp:662
general_slice_view_type top_right(index_type nr, index_type nc) const
Get a view of the top-right nr by nc block of the matrices.
Definition view.hpp:509
std::conditional_t< is_row_major, View, general_slice_view_type > col_slice_view_type
Definition view.hpp:68
void copy_values(const Other &other) const
Definition view.hpp:594
View & reassign(View other)
Reassign the buffer and layout of this view to those of another view. No data is copied.
Definition view.hpp:114
constexpr index_type outer_stride() const
Outer stride of the matrices (leading dimension in BLAS parlance).
Definition view.hpp:333
batch_view_type batch(index_type b) const
Access a batch of batch_size() layers, starting at batch index b (i.e.
Definition view.hpp:137
POD helper struct to enable designated initializers during construction.
Definition view.hpp:82