[linalg.layout.packed]

# 29 Numerics library [[numerics]](./#numerics)

## 29.9 Basic linear algebra algorithms [[linalg]](linalg#layout.packed)

### 29.9.6 Layouts for packed matrix types [linalg.layout.packed]

#### [29.9.6.1](#overview) Overview [[linalg.layout.packed.overview]](linalg.layout.packed.overview)

[1](#overview-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12015)

layout_blas_packed is an mdspan layout mapping policy
that represents a square matrix that stores only the entries in one
triangle, in a packed contiguous format[.](#overview-1.sentence-1)

Its Triangle template parameter determines
whether an mdspan with this layout
stores the upper or lower triangle of the matrix[.](#overview-1.sentence-2)

Its StorageOrder template parameter determines
whether the layout packs the matrix's elements
in column-major or row-major order[.](#overview-1.sentence-3)

[2](#overview-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12026)

A StorageOrder of column_major_t indicates column-major ordering[.](#overview-2.sentence-1)

This packs matrix elements
starting with the leftmost (least column index) column, and
proceeding column by column, from the top entry (least row index)[.](#overview-2.sentence-2)

[3](#overview-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12033)

A StorageOrder of row_major_t indicates row-major ordering[.](#overview-3.sentence-1)

This packs matrix elements
starting with the topmost (least row index) row, and
proceeding row by row, from the leftmost (least column index) entry[.](#overview-3.sentence-2)

[4](#overview-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12040)

[*Note [1](#overview-note-1)*:

layout_blas_packed describes the data layout used by
the BLAS'
Symmetric Packed (SP), Hermitian Packed (HP), and Triangular Packed (TP)
matrix types[.](#overview-4.sentence-1)

â *end note*]

namespace std::linalg {template<class Triangle, class StorageOrder>class [layout_blas_packed](#lib:layout_blas_packed "29.9.6.1 Overview [linalg.layout.packed.overview]") {public:using triangle_type = Triangle; using storage_order_type = StorageOrder; template<class Extents>struct mapping {public:using extents_type = Extents; using index_type = typename extents_type::index_type; using size_type = typename extents_type::size_type; using rank_type = typename extents_type::rank_type; using layout_type = layout_blas_packed; // [[linalg.layout.packed.cons]](#cons "29.9.6.2 Constructors"), constructorsconstexpr mapping() noexcept = default; constexpr mapping(const mapping&) noexcept = default; constexpr mapping(const extents_type&) noexcept; template<class OtherExtents>constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const mapping<OtherExtents>& other) noexcept; constexpr mapping& operator=(const mapping&) noexcept = default; // [[linalg.layout.packed.obs]](#obs "29.9.6.3 Observers"), observersconstexpr const extents_type& extents() const noexcept { return *extents_*; }constexpr index_type required_span_size() const noexcept; template<class Index0, class Index1>constexpr index_type operator() (Index0 ind0, Index1 ind1) const noexcept; static constexpr bool is_always_unique() noexcept {return (extents_type::static_extent(0) != dynamic_extent && extents_type::static_extent(0) < 2) ||(extents_type::static_extent(1) != dynamic_extent && extents_type::static_extent(1) < 2); }static constexpr bool is_always_exhaustive() noexcept { return true; }static constexpr bool is_always_strided() noexcept{ return is_always_unique(); }constexpr bool is_unique() const noexcept {return *extents_*.extent(0) < 2; }constexpr bool is_exhaustive() const noexcept { return true; }constexpr bool is_strided() const noexcept {return *extents_*.extent(0) < 2; }constexpr index_type stride(rank_type) const noexcept; template<class OtherExtents>friend constexpr bool operator==(const mapping&, const mapping<OtherExtents>&) noexcept; private: extents_type *extents_*{}; // *exposition only*}; };}

[5](#overview-5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12113)

*Mandates*: 

- [(5.1)](#overview-5.1)

Triangle is either upper_triangle_t or lower_triangle_t,

- [(5.2)](#overview-5.2)

StorageOrder is either column_major_t or row_major_t,

- [(5.3)](#overview-5.3)

Extents is a specialization of std​::​extents,

- [(5.4)](#overview-5.4)

Extents​::​rank() equals 2,

- [(5.5)](#overview-5.5)

one ofextents_type::static_extent(0) == dynamic_extent, extents_type::static_extent(1) == dynamic_extent, or extents_type::static_extent(0) == extents_type::static_extent(1) is true, and

- [(5.6)](#overview-5.6)

if Extents​::​rank_dynamic() == 0 is true,
let Ns be equal to Extents​::​static_extent(0); then,NsÃ(Ns+1) is representable as a value of type index_type[.](#overview-5.sentence-1)

[6](#overview-6)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12138)

layout_blas_packed<T, SO>​::​mapping<E> is a trivially copyable type
that models [regular](concepts.object#concept:regular "18.6 Object concepts [concepts.object]") for each T, SO, and E[.](#overview-6.sentence-1)

#### [29.9.6.2](#cons) Constructors [[linalg.layout.packed.cons]](linalg.layout.packed.cons)

[ð](#lib:layout_blas_packed::mapping,constructor)

`constexpr mapping(const extents_type& e) noexcept;
`

[1](#cons-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12151)

*Preconditions*: 

- [(1.1)](#cons-1.1)

  Let N be equal to e.extent(0)[.](#cons-1.1.sentence-1)
  Then, NÃ(N+1) is representable as
a value of type index_type ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types"))[.](#cons-1.1.sentence-2)

- [(1.2)](#cons-1.2)

  e.extent(0) equals e.extent(1)[.](#cons-1.2.sentence-1)

[2](#cons-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12162)

*Effects*: Direct-non-list-initializes *extents_* with e[.](#cons-2.sentence-1)

[ð](#lib:layout_blas_packed::mapping,constructor_)

`template<class OtherExtents>
  explicit(!is_convertible_v<OtherExtents, extents_type>)
    constexpr mapping(const mapping<OtherExtents>& other) noexcept;
`

[3](#cons-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12175)

*Constraints*: is_constructible_v<extents_type, OtherExtents> is true[.](#cons-3.sentence-1)

[4](#cons-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12179)

*Preconditions*: Let N be other.extents().extent(0)[.](#cons-4.sentence-1)

Then, NÃ(N+1) is representable as
a value of type index_type ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types"))[.](#cons-4.sentence-2)

[5](#cons-5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12185)

*Effects*: Direct-non-list-initializes *extents_* with other.extents()[.](#cons-5.sentence-1)

#### [29.9.6.3](#obs) Observers [[linalg.layout.packed.obs]](linalg.layout.packed.obs)

[ð](#lib:layout_blas_packed::mapping,required_span_size)

`constexpr index_type required_span_size() const noexcept;
`

[1](#obs-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12198)

*Returns*: *extents_*.extent(0) * (*extents_*.extent(0) + 1)/2[.](#obs-1.sentence-1)

[*Note [1](#obs-note-1)*:

For example, a 5 x 5 packed matrix
only stores 15 matrix elements[.](#obs-1.sentence-2)

â *end note*]

[ð](#lib:layout_blas_packed::mapping,operator())

`template<class Index0, class Index1>
  constexpr index_type operator() (Index0 ind0, Index1 ind1) const noexcept;
`

[2](#obs-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12214)

*Constraints*: 

- [(2.1)](#obs-2.1)

is_convertible_v<Index0, index_type> is true,

- [(2.2)](#obs-2.2)

is_convertible_v<Index1, index_type> is true,

- [(2.3)](#obs-2.3)

is_nothrow_constructible_v<index_type, Index0> is true, and

- [(2.4)](#obs-2.4)

is_nothrow_constructible_v<index_type, Index1> is true[.](#obs-2.sentence-1)

[3](#obs-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12227)

Let i be extents_type​::​*index-cast*(ind0), and
let j be extents_type​::​*index-cast*(ind1)[.](#obs-3.sentence-1)

[4](#obs-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12231)

*Preconditions*: i, j is a multidimensional index in *extents_* ([[mdspan.overview]](mdspan.overview "23.7.3.1 Overview"))[.](#obs-4.sentence-1)

[5](#obs-5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12236)

*Returns*: Let N be *extents_*.extent(0)[.](#obs-5.sentence-1)

Then

- [(5.1)](#obs-5.1)

(*this)(j, i) if i > j is true; otherwise

- [(5.2)](#obs-5.2)

i + j * (j + 1)/2 ifis_same_v<StorageOrder, column_major_t> && is_same_v<Triangle, upper_triangle_t> is true oris_same_v<StorageOrder, row_major_t> && is_same_v<Triangle, lower_triangle_t> is true; otherwise

- [(5.3)](#obs-5.3)

j + N * i - i * (i + 1)/2[.](#obs-5.sentence-2)

[ð](#lib:layout_blas_packed::mapping,stride)

`constexpr index_type stride(rank_type r) const noexcept;
`

[6](#obs-6)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12264)

*Preconditions*: 

- [(6.1)](#obs-6.1)

is_strided() is true, and

- [(6.2)](#obs-6.2)

r < extents_type​::​rank() is true[.](#obs-6.sentence-1)

[7](#obs-7)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12273)

*Returns*: 1[.](#obs-7.sentence-1)

[ð](#lib:layout_blas_packed::mapping,operator==)

`template<class OtherExtents>
  friend constexpr bool operator==(const mapping& x, const mapping<OtherExtents>& y) noexcept;
`

[8](#obs-8)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/numerics.tex#L12285)

*Effects*: Equivalent to: return x.extents() == y.extents();
