Files
cppdraft_translate/cppdraft/linalg/helpers.md
2025-10-25 03:02:53 +03:00

193 lines
15 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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.9Basic 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.5Argument concepts[linalg.helpers.concepts]") =*is-mdspan*<T> && T::rank() == 1;
template<class T>concept [*out-vector*](#concept:out-vector "29.9.7.5Argument 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.5Argument 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.5Argument concepts[linalg.helpers.concepts]") =*is-mdspan*<T> && T::rank() == 2;
template<class T>concept [*out-matrix*](#concept:out-matrix "29.9.7.5Argument 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.5Argument 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.5Argument 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.5Argument 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.5Argument 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.5Argument 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.9Basic linear algebra algorithms") accesses the elements
of a parameter constrained by[*in-vector*](#concept:in-vector "29.9.7.5Argument concepts[linalg.helpers.concepts]"),[*in-matrix*](#concept:in-matrix "29.9.7.5Argument concepts[linalg.helpers.concepts]"), or[*in-object*](#concept:in-object "29.9.7.5Argument 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.5Argument concepts[linalg.helpers.concepts]"),[*inout-matrix*](#concept:inout-matrix "29.9.7.5Argument concepts[linalg.helpers.concepts]"),[*inout-object*](#concept:inout-object "29.9.7.5Argument concepts[linalg.helpers.concepts]"),[*out-vector*](#concept:out-vector "29.9.7.5Argument concepts[linalg.helpers.concepts]"),[*out-matrix*](#concept:out-matrix "29.9.7.5Argument concepts[linalg.helpers.concepts]"),[*out-object*](#concept:out-object "29.9.7.5Argument concepts[linalg.helpers.concepts]"), or[*possibly-packed-inout-matrix*](#concept:possibly-packed-inout-matrix "29.9.7.5Argument concepts[linalg.helpers.concepts]") parameter of a function in [[linalg]](linalg "29.9Basic 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.5Argument concepts[linalg.helpers.concepts]") In1, [*in-vector*](#concept:in-vector "29.9.7.5Argument concepts[linalg.helpers.concepts]") In2, [*in-vector*](#concept:in-vector "29.9.7.5Argument 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.5Argument concepts[linalg.helpers.concepts]") In1, [*in-matrix*](#concept:in-matrix "29.9.7.5Argument concepts[linalg.helpers.concepts]") In2, [*in-matrix*](#concept:in-matrix "29.9.7.5Argument 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.5Argument concepts[linalg.helpers.concepts]") InMat, [*in-vector*](#concept:in-vector "29.9.7.5Argument concepts[linalg.helpers.concepts]") InVec, [*in-vector*](#concept:in-vector "29.9.7.5Argument 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.5Argument concepts[linalg.helpers.concepts]") InVec, [*in-matrix*](#concept:in-matrix "29.9.7.5Argument concepts[linalg.helpers.concepts]") InMat, [*in-vector*](#concept:in-vector "29.9.7.5Argument 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.5Argument concepts[linalg.helpers.concepts]") InMat1, [*in-matrix*](#concept:in-matrix "29.9.7.5Argument concepts[linalg.helpers.concepts]") InMat2, [*in-matrix*](#concept:in-matrix "29.9.7.5Argument 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.5Argument concepts[linalg.helpers.concepts]") auto& in1, const [*in-vector*](#concept:in-vector "29.9.7.5Argument concepts[linalg.helpers.concepts]") auto& in2, const [*in-vector*](#concept:in-vector "29.9.7.5Argument 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.5Argument concepts[linalg.helpers.concepts]") auto& in1, const [*in-matrix*](#concept:in-matrix "29.9.7.5Argument concepts[linalg.helpers.concepts]") auto& in2, const [*in-matrix*](#concept:in-matrix "29.9.7.5Argument 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.5Argument concepts[linalg.helpers.concepts]") auto& in_mat, const [*in-vector*](#concept:in-vector "29.9.7.5Argument concepts[linalg.helpers.concepts]") auto& in_vec, const [*in-vector*](#concept:in-vector "29.9.7.5Argument 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.5Argument concepts[linalg.helpers.concepts]") auto& in_vec, const [*in-matrix*](#concept:in-matrix "29.9.7.5Argument concepts[linalg.helpers.concepts]") auto& in_mat, const [*in-vector*](#concept:in-vector "29.9.7.5Argument 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.5Argument concepts[linalg.helpers.concepts]") auto& in_mat1, const [*in-matrix*](#concept:in-matrix "29.9.7.5Argument concepts[linalg.helpers.concepts]") auto& in_mat2, const [*in-matrix*](#concept:in-matrix "29.9.7.5Argument 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);}