I think there are a few issues with the vector_sum_of_squares wording, in addition to #141 and #144. The essence is that (1) the exact value of the scaling factor ought to be QoI detail and (2) there's no formal requirement that division or square root be defined for the Scalar type.
I've drafted the following LWG issue. I was wondering if anyone has any comments before I submit it, or would like to collaborate on writing it.
Discussion
The Effects of vector_sum_of_squares are both too strong and too weak. They are too weak because that function is not a triangular solve algorithm, so there is no requirement that it be possible to divide two values, and without division it is impossible to calculate the scaled sum-of-squares. They are too strong because they describe precisely what value result.scaling_factor must have, but implementations should have freedom to choose this as needed to avoid unnecessary under- or overflow. Notably, the reference BLAS stopped using this prescription in 2021 (see Reference-LAPACK/lapack#494). An implementation may also prefer to scale by a power of the floating-point radix, because this can be done exactly.
The specifications of [linalg.algs.blas1.nrm2] and [linalg.algs.blas1.matfrobnorm] are also too weak because they could mandate that it be possible to take the square root of a Scalar but don't, and that operation is inherent in the function's definition.
Proposed resolution
[linalg.general]
-7- Within all the functions in [linalg], square roots shall be calculated with an unqualified call to sqrt, with overload resolution performed in a context that includes the declaration template<class U> U sqrt(const U&) = delete;.
[linalg.reqs.alg]/2.2
The triangular solve algorithms in [linalg.algs.blas1.ssq], [linalg.algs.blas2.trsv], [linalg.algs.blas3.trmm], [linalg.algs.blas3.trsm], and [linalg.algs.blas3.inplacetrsm] either [...]
[linalg.algs.blas1.ssq]/3
Effects: Returns a value result such that
(3.1) — result.scaling_factor is the maximum of init.scaling_factor and abs-if-needed(x[i]) for all i in the domain of v; and
(3.2) — letif s2init be is
init.scaling_factor * init.scaling_factor * init.scaled_sum_of_squares
then [...]
[linalg.algs.blas1.nrm2]/2
Mandates: decltype(sqrt(abs-if-needed(declval<typename InVec::value_type>()))) is convertible to Scalar.
[linalg.algs.blas1.matfrobnorm]
Mandates: Let a be abs-if-needed(declval<typename InMat::value_type>()). Then, decltype(sqrt(init + a * a)) is convertible to Scalar.
I think there are a few issues with the
vector_sum_of_squareswording, in addition to #141 and #144. The essence is that (1) the exact value of the scaling factor ought to be QoI detail and (2) there's no formal requirement that division or square root be defined for theScalartype.I've drafted the following LWG issue. I was wondering if anyone has any comments before I submit it, or would like to collaborate on writing it.
Discussion
The Effects of
vector_sum_of_squaresare both too strong and too weak. They are too weak because that function is not a triangular solve algorithm, so there is no requirement that it be possible to divide two values, and without division it is impossible to calculate the scaled sum-of-squares. They are too strong because they describe precisely what valueresult.scaling_factormust have, but implementations should have freedom to choose this as needed to avoid unnecessary under- or overflow. Notably, the reference BLAS stopped using this prescription in 2021 (see Reference-LAPACK/lapack#494). An implementation may also prefer to scale by a power of the floating-point radix, because this can be done exactly.The specifications of [linalg.algs.blas1.nrm2] and [linalg.algs.blas1.matfrobnorm] are also too weak because they could mandate that it be possible to take the square root of a
Scalarbut don't, and that operation is inherent in the function's definition.Proposed resolution
[linalg.general]
-7- Within all the functions in [linalg], square roots shall be calculated with an unqualified call to
sqrt, with overload resolution performed in a context that includes the declarationtemplate<class U> U sqrt(const U&) = delete;.[linalg.reqs.alg]/2.2
The triangular solve algorithms in [linalg.algs.blas1.ssq], [linalg.algs.blas2.trsv], [linalg.algs.blas3.trmm], [linalg.algs.blas3.trsm], and [linalg.algs.blas3.inplacetrsm] either [...]
[linalg.algs.blas1.ssq]/3
Effects: Returns a value result such that
(3.1) — result.scaling_factor is the maximum of init.scaling_factor and abs-if-needed(x[i]) for all i in the domain of v; and(3.2) — letifs2initbeisinit.scaling_factor * init.scaling_factor * init.scaled_sum_of_squaresthen [...]
[linalg.algs.blas1.nrm2]/2
Mandates:
decltype(sqrt(abs-if-needed(declval<typename InVec::value_type>())))is convertible toScalar.[linalg.algs.blas1.matfrobnorm]
Mandates: Let
abeabs-if-needed(declval<typename InMat::value_type>()). Then,decltype(sqrt(init + a * a))is convertible toScalar.