Open mhoemmen opened 1 year ago
Idea for unifying mandates and preconditions further:
template<out-matrix Out, in-matrix In1, in-matrix In2>
constexpr bool possibly-elementwise-combinable() {
bool out_in1_ext0 =
Out::static_extent(0) == dynamic_extent || In1::static_extent(0) == dynamic_extent ||
Out::static_extent(0) == In1::static_extent(0));
bool out_in1_ext1 =
Out::static_extent(1) == dynamic_extent || In1::static_extent(1) == dynamic_extent ||
Out::static_extent(1) == In1::static_extent(1));
bool out_in2_ext0 =
Out::static_extent(0) == dynamic_extent || In2::static_extent(0) == dynamic_extent ||
Out::static_extent(0) == In2::static_extent(0));
bool out_in2_ext1 =
Out::static_extent(1) == dynamic_extent || In2::static_extent(1) == dynamic_extent ||
Out::static_extent(1) == In2::static_extent(1));
bool in1_in2_ext0 =
In1::static_extent(0) == dynamic_extent || In2::static_extent(0) == dynamic_extent ||
In1::static_extent(0) == In2::static_extent(0));
bool in1_in2_ext1 =
In1::static_extent(1) == dynamic_extent || In2::static_extent(1) == dynamic_extent ||
In1::static_extent(1) == In2::static_extent(1));
return out_in1_ext0 && out_in1_ext1 && out_in2_ext0 && out_in2_ext1 && in1_in2_ext0 && in1_in2_ext1;
}
template<out-vector Out, in-vector In1, in-vector In2>
constexpr bool possibly-elementwise-combinable() {
bool out_in1_ext0 =
Out::static_extent(0) == dynamic_extent || In1::static_extent(0) == dynamic_extent ||
Out::static_extent(0) == In1::static_extent(0));
bool out_in2_ext0 =
Out::static_extent(0) == dynamic_extent || In2::static_extent(0) == dynamic_extent ||
Out::static_extent(0) == In2::static_extent(0));
bool in1_in2_ext0 =
In1::static_extent(0) == dynamic_extent || In2::static_extent(0) == dynamic_extent ||
In1::static_extent(0) == In2::static_extent(0));
return out_in1_ext0 && out_in2_ext0 && in1_in2_ext0;
}
template<out-vector Out, in-matrix In1, in-vector In2>
constexpr bool possibly-multiplyable() {
bool out_in1 =
Out::static_extent(0) == dynamic_extent || In1::static_extent(0) == dynamic_extent ||
Out::static_extent(0) == In1::static_extent(0));
bool in1_in2 =
In1::static_extent(1) == dynamic_extent || In2::static_extent(0) == dynamic_extent ||
In1::static_extent(1) == In2::static_extent(0));
return out_in1 && in1_in2;
}
template<out-vector Out, in-vector In1, in-matrix In2>
constexpr bool possibly-multiplyable() {
bool out_in2 =
Out::static_extent(0) == dynamic_extent || In2::static_extent(1) == dynamic_extent ||
Out::static_extent(0) == In2::static_extent(1));
bool in1_in2 =
In1::static_extent(0) == dynamic_extent || In2::static_extent(0) == dynamic_extent ||
In1::static_extent(0) == In2::static_extent(0));
return out_in1 && in1_in2;
}
template<out-matrix Out, in-matrix In1, in-matrix In2>
constexpr bool elementwise-combinable(Out out, In1 in1, In2 in2) {
return out.extent(0) == in1.extent(0) && in1.extent(0) == in2.extent(0) &&
out.extent(1) == in1.extent(1) && in1.extent(1) == in2.extent(1);
}
template<out-vector Out, in-vector In1, in-vector In2>
constexpr bool elementwise-combinable(Out out, In1 in1, In2 in2) {
return out.extent(0) == in1.extent(0) && in1.extent(0) == in2.extent(0);
}
template<out-vector Out, in-matrix In1, in-vector In2>
constexpr bool multiplyable(Out out, In1 in1, In2 in2) {
return out.extent(0) == in1.extent(0) &&
in1.extent(1) === in2.extent(0);
}
template<out-vector Out, in-vector In1, in-matrix In2>
constexpr bool multiplyable(Out out, In1 in1, In2 in2) {
return out.extent(0) == in2.extent(1) &&
in1.extent(0) === in2.extent(0);
}
With these guys we can write the mandates and preconditions a bit simpler for matrix-vector-product:
Mandates: possibly-multiplyable<OutVec, InMat, InVec>()
Preconditions: multiplyable(y, A, x)
LWG review of P1673R12: 2023/06/28
linalg.algs.reqs
2.4, spell out "unary plus" as well as unary minus.
Not comfortable with saying that "any addend" is well formed, as that just says a value is well formed, rather than an expression on it. That mixes just an operand (value), which can't be well formed or ill formed, and operations on them, which can be. Addend could just be a subexpression. "Any addend expression," "any subtrahend expression." -- works. OR: "is a well-formed expression" instead of "is well formed." Just change "is well formed" to "is a well-formed expression," in 2.4 and 2.5.
2.5 etc. doesn't affect overload resolution. It's a precondition, not a constraint.
Should we separate "core linear algebra value types" vs. "bring your own," for the sake of specification? Or add a note: "arithmetic types fulfil these requirements trivially"? complex and int don't interoperate. Compare with duration's "emulating an arithmetic type" (where nobody has any idea what it actually means) -- where we separate standard and user-provided types.
linalg.reqs.flpt
Demmel 2007, not Demmel 2002.
Editorial: can remove parentheses; doesn't need them, just part of sentence.
"Performing floating-point operations on floating-point" is not observable. Isn't the implementer already allowed to do 2.1, 2.2, or 2.3? But this is about the implementation of the algorithms, not about the types. But the user can't observe that. This is thus more like an implementer note.
2.4 is implied. 2.5 is actually useful.
Regarding Demmel 2007: Normative references can't be in bibliography. Can we paste the definition here? Otherwise, it needs to be in the normative reference section. It's OK to use the definition, because if floating point doesn't behave with bounded rounding, under the simple assumptions of Demmel 2007, then the definition is vacuous.
For special math functions, it's all just QoI. Just make it a Note.
linalg.algs.blas2
Introduce a new heading, e.g., gemm.intro, before the Note. Otherwise, it's a hanging paragraph. We had the same issue in mdspan.
(para 4) Complexity: "For all algorithms in [linalg.algs.blas2] ... the number of ... is linear in ...." In general, use the stable tag instead of "in this Clause" etc.
It's OK to use "equals" to express a statement of truth. (
A.extent(1) == x.extent(0)
istrue
is also fine.)It's clear that dimension checking should be Mandates. Should we try to express the Mandates as a concept? (After the LWG meeting, Christian and I decided to explore this. We could implement it as two functions: constexpr function to check compile-time extents (for Mandates), and a function to check run-time dimensions (for Preconditions). Don't change paper yet; just implement wording to show them, and ask. The idea is that we could reuse function definitions and thus save wording (and also give a good hint for how the checks could be implemented).)
Next time (in two weeks)
Review 17.11.3.1 linalg.algs.blas2.gemv.