[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 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 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 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 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) templateconstexpr bool *is-mdspan* = false; templateconstexpr bool *is-mdspan*> = true; templateconcept [*in-vector*](#concept:in-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan* && T::rank() == 1; templateconcept [*out-vector*](#concept:out-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan* && T::rank() == 1 && is_assignable_v && T::is_always_unique(); templateconcept [*inout-vector*](#concept:inout-vector "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan* && T::rank() == 1 && is_assignable_v && T::is_always_unique(); templateconcept [*in-matrix*](#concept:in-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan* && T::rank() == 2; templateconcept [*out-matrix*](#concept:out-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan* && T::rank() == 2 && is_assignable_v && T::is_always_unique(); templateconcept [*inout-matrix*](#concept:inout-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan* && T::rank() == 2 && is_assignable_v && T::is_always_unique(); templateconstexpr bool *is-layout-blas-packed* = false; // *exposition only*templateconstexpr bool *is-layout-blas-packed*> = true; templateconcept [*possibly-packed-inout-matrix*](#concept:possibly-packed-inout-matrix "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan* && T::rank() == 2 && is_assignable_v &&(T::is_always_unique() || *is-layout-blas-packed*); templateconcept [*in-object*](#concept:in-object "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan* && (T::rank() == 1 || T::rank() == 2); templateconcept [*out-object*](#concept:out-object "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan* && (T::rank() == 1 || T::rank() == 2) && is_assignable_v && T::is_always_unique(); templateconcept [*inout-object*](#concept:inout-object "29.9.7.5 Argument concepts [linalg.helpers.concepts]") =*is-mdspan* && (T::rank() == 1 || T::rank() == 2) && is_assignable_v && 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*] templaterequires(*is-mdspan* && *is-mdspan*)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*(0, 0) &&*compatible-static-extents*(0, 0) &&*compatible-static-extents*(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*(0, 0) &&*compatible-static-extents*(1, 1) &&*compatible-static-extents*(0, 0) &&*compatible-static-extents*(1, 1) &&*compatible-static-extents*(0, 0) &&*compatible-static-extents*(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*(0, 0) &&*compatible-static-extents*(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*(0, 1) &&*compatible-static-extents*(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*(0, 0) &&*compatible-static-extents*(1, 1) &&*compatible-static-extents*(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);}