193 lines
15 KiB
Markdown
193 lines
15 KiB
Markdown
[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);}
|