[linalg.helpers]

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

## 29.9 Basic linear algebra algorithms [[linalg]](linalg#helpers)

### 29.9.7 Exposition-only helpers [linalg.helpers]

#### [29.9.7.1](#abs) *abs-if-needed* [[linalg.helpers.abs]](linalg.helpers.abs)

[1](#abs-1)

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

The name *abs-if-needed* denotes an exposition-only function object[.](#abs-1.sentence-1)

The expression *abs-if-needed*(E) for a subexpression E whose type is T is expression-equivalent to:

- [(1.1)](#abs-1.1)

E if T is an unsigned integer;

- [(1.2)](#abs-1.2)

otherwise, std​::​abs(E) if T is an arithmetic type,

- [(1.3)](#abs-1.3)

otherwise, abs(E),
if that expression is valid,
with overload resolution performed in a context that includes the declarationtemplate<class U> U abs(U) = delete;
   If the function selected by overload resolution
does not return the absolute value of its input,
the program is ill-formed, no diagnostic required[.](#abs-1.3.sentence-2)

#### [29.9.7.2](#conj) *conj-if-needed* [[linalg.helpers.conj]](linalg.helpers.conj)

[1](#conj-1)

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

The name *conj-if-needed* denotes an exposition-only function object[.](#conj-1.sentence-1)

The expression *conj-if-needed*(E) for a subexpression E whose type is T is expression-equivalent to:

- [(1.1)](#conj-1.1)

conj(E),
if T is not an arithmetic type and
the expression conj(E) is valid,
with overload resolution performed in a context that includes the declarationtemplate<class U> U conj(const U&) = delete;
   If the function selected by overload resolution
does not return the complex conjugate of its input,
the program is ill-formed, no diagnostic required;

- [(1.2)](#conj-1.2)

otherwise, E[.](#conj-1.sentence-2)

#### [29.9.7.3](#real) *real-if-needed* [[linalg.helpers.real]](linalg.helpers.real)

[1](#real-1)

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

The name *real-if-needed* denotes an exposition-only function object[.](#real-1.sentence-1)

The expression *real-if-needed*(E) for a subexpression E whose type is T is expression-equivalent to:

- [(1.1)](#real-1.1)

real(E),
if T is not an arithmetic type and
the expression real(E) is valid,
with overload resolution performed in a context that includes the declarationtemplate<class U> U real(const U&) = delete;
   If the function selected by overload resolution
does not return the real part of its input,
the program is ill-formed, no diagnostic required;

- [(1.2)](#real-1.2)

otherwise, E[.](#real-1.sentence-2)

#### [29.9.7.4](#imag) *imag-if-needed* [[linalg.helpers.imag]](linalg.helpers.imag)

[1](#imag-1)

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

The name *imag-if-needed* denotes an exposition-only function object[.](#imag-1.sentence-1)

The expression *imag-if-needed*(E) for a subexpression E whose type is T is expression-equivalent to:

- [(1.1)](#imag-1.1)

imag(E),
if T is not an arithmetic type and the expression imag(E) is valid, with overload resolution performed in a context
that includes the declarationtemplate<class U> U imag(const U&) = delete;
   If the function selected by overload resolution
does not return the imaginary part of its input,
the program is ill-formed, no diagnostic required;

- [(1.2)](#imag-1.2)

otherwise, ((void)E, T{})[.](#imag-1.sentence-2)

#### [29.9.7.5](#concepts) Argument concepts [[linalg.helpers.concepts]](linalg.helpers.concepts)

[1](#concepts-1)

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

The exposition-only concepts defined in this section
constrain the algorithms in [[linalg]](linalg "29.9 Basic linear algebra algorithms")[.](#concepts-1.sentence-1)

template<class T>constexpr bool *is-mdspan* = false;

template<class ElementType, class Extents, class Layout, class Accessor>constexpr bool *is-mdspan*<mdspan<ElementType, Extents, Layout, Accessor>> = true;

template<class T>concept [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan*<T> && T::rank() == 1;

template<class T>concept [*out-vector*](#concept:out-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan*<T> && T::rank() == 1 && is_assignable_v<typename T::reference, typename T::element_type> && T::is_always_unique();

template<class T>concept [*inout-vector*](#concept:inout-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan*<T> && T::rank() == 1 && is_assignable_v<typename T::reference, typename T::element_type> && T::is_always_unique();

template<class T>concept [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan*<T> && T::rank() == 2;

template<class T>concept [*out-matrix*](#concept:out-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan*<T> && T::rank() == 2 && is_assignable_v<typename T::reference, typename T::element_type> && T::is_always_unique();

template<class T>concept [*inout-matrix*](#concept:inout-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan*<T> && T::rank() == 2 && is_assignable_v<typename T::reference, typename T::element_type> && T::is_always_unique();

template<class T>constexpr bool *is-layout-blas-packed* = false; // *exposition only*template<class Triangle, class StorageOrder>constexpr bool *is-layout-blas-packed*<layout_blas_packed<Triangle, StorageOrder>> = true;

template<class T>concept [*possibly-packed-inout-matrix*](#concept:possibly-packed-inout-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan*<T> && T::rank() == 2 && is_assignable_v<typename T::reference, typename T::element_type> &&(T::is_always_unique() || *is-layout-blas-packed*<typename T::layout_type>);

template<class T>concept [*in-object*](#concept:in-object "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan*<T> && (T::rank() == 1 || T::rank() == 2);

template<class T>concept [*out-object*](#concept:out-object "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan*<T> && (T::rank() == 1 || T::rank() == 2) && is_assignable_v<typename T::reference, typename T::element_type> && T::is_always_unique();

template<class T>concept [*inout-object*](#concept:inout-object "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan*<T> && (T::rank() == 1 || T::rank() == 2) && is_assignable_v<typename T::reference, typename T::element_type> && T::is_always_unique();

[2](#concepts-2)

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

If a function in [[linalg]](linalg "29.9 Basic linear algebra algorithms") accesses the elements
of a parameter constrained by[*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]"),[*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]"), or[*in-object*](#concept:in-object "29.9.7.5 Argument concepts [linalg.helpers.concepts]"),
those accesses will not modify the elements[.](#concepts-2.sentence-1)

[3](#concepts-3)

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

Unless explicitly permitted, any[*inout-vector*](#concept:inout-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]"),[*inout-matrix*](#concept:inout-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]"),[*inout-object*](#concept:inout-object "29.9.7.5 Argument concepts [linalg.helpers.concepts]"),[*out-vector*](#concept:out-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]"),[*out-matrix*](#concept:out-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]"),[*out-object*](#concept:out-object "29.9.7.5 Argument concepts [linalg.helpers.concepts]"), or[*possibly-packed-inout-matrix*](#concept:possibly-packed-inout-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") parameter of a function in [[linalg]](linalg "29.9 Basic linear algebra algorithms") shall not overlap any other mdspan parameter of the function[.](#concepts-3.sentence-1)

#### [29.9.7.6](#mandates) Mandates [[linalg.helpers.mandates]](linalg.helpers.mandates)

[1](#mandates-1)

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

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

These exposition-only helper functions use
the less constraining input concepts even for the output arguments,
because the additional constraint for assignability of elements
is not necessary, and
they are sometimes used in a context
where the third argument is an input type too[.](#mandates-1.sentence-1)

â *end note*]

template<class MDS1, class MDS2>requires(*is-mdspan*<MDS1> && *is-mdspan*<MDS2>)constexprbool *compatible-static-extents*(size_t r1, size_t r2) { // *exposition only*return MDS1::static_extent(r1) == dynamic_extent || MDS2::static_extent(r2) == dynamic_extent || MDS1::static_extent(r1) == MDS2::static_extent(r2); }template<[*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") In1, [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") In2, [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") Out>constexpr bool *possibly-addable*() { // *exposition only*return *compatible-static-extents*<Out, In1>(0, 0) &&*compatible-static-extents*<Out, In2>(0, 0) &&*compatible-static-extents*<In1, In2>(0, 0); }template<[*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") In1, [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") In2, [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") Out>constexpr bool *possibly-addable*() { // *exposition only*return *compatible-static-extents*<Out, In1>(0, 0) &&*compatible-static-extents*<Out, In1>(1, 1) &&*compatible-static-extents*<Out, In2>(0, 0) &&*compatible-static-extents*<Out, In2>(1, 1) &&*compatible-static-extents*<In1, In2>(0, 0) &&*compatible-static-extents*<In1, In2>(1, 1); }template<[*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") InMat, [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") InVec, [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") OutVec>constexpr bool *possibly-multipliable*() { // *exposition only*return *compatible-static-extents*<OutVec, InMat>(0, 0) &&*compatible-static-extents*<InMat, InVec>(1, 0); }template<[*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") InVec, [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") InMat, [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") OutVec>constexpr bool *possibly-multipliable*() { // *exposition only*return *compatible-static-extents*<OutVec, InMat>(0, 1) &&*compatible-static-extents*<InMat, InVec>(0, 0); }template<[*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") InMat1, [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") InMat2, [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") OutMat>constexpr bool *possibly-multipliable*() { // *exposition only*return *compatible-static-extents*<OutMat, InMat1>(0, 0) &&*compatible-static-extents*<OutMat, InMat2>(1, 1) &&*compatible-static-extents*<InMat1, InMat2>(1, 0); }

#### [29.9.7.7](#precond) Preconditions [[linalg.helpers.precond]](linalg.helpers.precond)

[1](#precond-1)

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

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

These exposition-only helper functions use
the less constraining input concepts even for the output arguments,
because the additional constraint for assignability of elements
is not necessary, and
they are sometimes used in a context
where the third argument is an input type too[.](#precond-1.sentence-1)

â *end note*]

constexpr bool *addable*( // *exposition only*const [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& in1, const [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& in2, const [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& out) {return out.extent(0) == in1.extent(0) && out.extent(0) == in2.extent(0);}constexpr bool *addable*( // *exposition only*const [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& in1, const [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& in2, const [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& out) {return out.extent(0) == in1.extent(0) && out.extent(1) == in1.extent(1) && out.extent(0) == in2.extent(0) && out.extent(1) == in2.extent(1);}constexpr bool *multipliable*( // *exposition only*const [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& in_mat, const [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& in_vec, const [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& out_vec) {return out_vec.extent(0) == in_mat.extent(0) && in_mat.extent(1) == in_vec.extent(0);}constexpr bool *multipliable*( // *exposition only*const [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& in_vec, const [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& in_mat, const [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& out_vec) {return out_vec.extent(0) == in_mat.extent(1) && in_mat.extent(0) == in_vec.extent(0);}constexpr bool *multipliable*( // *exposition only*const [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& in_mat1, const [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& in_mat2, const [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") auto& out_mat) {return out_mat.extent(0) == in_mat1.extent(0) && out_mat.extent(1) == in_mat2.extent(1) && in_mat1.extent(1) == in_mat2.extent(0);}
