Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
matrix_op.hpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
10#pragma once
11
21
22#include "shambase/assert.hpp"
24#include "shambackends/math.hpp"
25#include "shambackends/sycl.hpp"
26#include <experimental/mdspan>
27#include <array>
28
29namespace shammath {
30
44 template<class T, class Extents, class Layout, class Accessor, class Func>
45 inline void mat_set_vals(const std::mdspan<T, Extents, Layout, Accessor> &input, Func &&func) {
46
48
49 for (int i = 0; i < input.extent(0); i++) {
50 for (int j = 0; j < input.extent(1); j++) {
51 input(i, j) = func(i, j);
52 }
53 }
54 }
55
67 template<class T, class Extents, class Layout, class Accessor, class Func>
68 inline void vec_set_vals(const std::mdspan<T, Extents, Layout, Accessor> &input, Func &&func) {
69
71
72 for (int i = 0; i < input.extent(0); i++) {
73 input(i) = func(i);
74 }
75 }
76
90 template<class T, class Extents, class Layout, class Accessor, class Func>
91 inline void mat_update_vals(
92 const std::mdspan<T, Extents, Layout, Accessor> &input, Func &&func) {
93
95
96 for (int i = 0; i < input.extent(0); i++) {
97 for (int j = 0; j < input.extent(1); j++) {
98 func(input(i, j), i, j);
99 }
100 }
101 }
102
114 template<class T, class Extents, class Layout, class Accessor>
115 inline void mat_set_identity(const std::mdspan<T, Extents, Layout, Accessor> &input1) {
116
117 SHAM_ASSERT(input1.extent(0) == input1.extent(1));
118
119 mat_set_vals(input1, [](auto i, auto j) -> T {
120 return (i == j) ? 1 : 0;
121 });
122 }
123
133 template<class T, class Extents, class Layout, class Accessor>
134 inline void mat_mul_scalar(
135 const std::mdspan<T, Extents, Layout, Accessor> &input, const T &scalar) {
136 mat_update_vals(input, [&](T &v, auto i, auto j) {
137 v *= scalar;
138 });
139 }
140
150 template<class T, class Extents, class Layout, class Accessor>
151 inline void mat_copy(
152 const std::mdspan<T, Extents, Layout, Accessor> &input,
153 const std::mdspan<T, Extents, Layout, Accessor> &output) {
154
155 SHAM_ASSERT(input.extent(0) == output.extent(0));
156 SHAM_ASSERT(input.extent(1) == output.extent(1));
157
158 for (int i = 0; i < input.extent(0); i++) {
159 for (int j = 0; j < input.extent(1); j++) {
160 output(i, j) = input(i, j);
161 }
162 }
163 }
164
176 template<
177 class T,
178 class Extents1,
179 class Extents2,
180 class Extents3,
181 class Layout1,
182 class Layout2,
183 class Layout3,
184 class Accessor1,
185 class Accessor2,
186 class Accessor3>
187 inline void mat_plus(
188 const std::mdspan<T, Extents1, Layout1, Accessor1> &input1,
189 const std::mdspan<T, Extents2, Layout2, Accessor2> &input2,
190 const std::mdspan<T, Extents3, Layout3, Accessor3> &output) {
191
192 SHAM_ASSERT(input1.extent(0) == output.extent(0));
193 SHAM_ASSERT(input1.extent(1) == output.extent(1));
194 SHAM_ASSERT(input1.extent(0) == input2.extent(0));
195 SHAM_ASSERT(input1.extent(1) == input2.extent(1));
196
197 for (int i = 0; i < input1.extent(0); i++) {
198 for (int j = 0; j < input1.extent(1); j++) {
199 output(i, j) = input1(i, j) + input2(i, j);
200 }
201 }
202 }
203
214 template<
215 class T,
216 class Extents1,
217 class Extents2,
218 class Layout1,
219 class Layout2,
220 class Accessor1,
221 class Accessor2>
222 inline void mat_plus_equal(
223 const std::mdspan<T, Extents1, Layout1, Accessor1> &inout,
224 const std::mdspan<T, Extents2, Layout2, Accessor2> &matb) {
225
226 SHAM_ASSERT(inout.extent(0) == inout.extent(0));
227 SHAM_ASSERT(inout.extent(1) == inout.extent(1));
228
229 for (int i = 0; i < inout.extent(0); i++) {
230 for (int j = 0; j < inout.extent(1); j++) {
231 inout(i, j) += matb(i, j);
232 }
233 }
234 }
235
247 template<
248 class T,
249 class Extents1,
250 class Extents2,
251 class Extents3,
252 class Layout1,
253 class Layout2,
254 class Layout3,
255 class Accessor1,
256 class Accessor2,
257 class Accessor3>
258 inline void mat_sub(
259 const std::mdspan<T, Extents1, Layout1, Accessor1> &input1,
260 const std::mdspan<T, Extents2, Layout2, Accessor2> &input2,
261 const std::mdspan<T, Extents3, Layout3, Accessor3> &output) {
262
263 SHAM_ASSERT(input1.extent(0) == output.extent(0));
264 SHAM_ASSERT(input1.extent(1) == output.extent(1));
265 SHAM_ASSERT(input1.extent(0) == input2.extent(0));
266 SHAM_ASSERT(input1.extent(1) == input2.extent(1));
267
268 for (int i = 0; i < input1.extent(0); i++) {
269 for (int j = 0; j < input1.extent(1); j++) {
270 output(i, j) = input1(i, j) - input2(i, j);
271 }
272 }
273 }
274
286 template<
287 class T,
288 class Extents1,
289 class Extents2,
290 class Layout1,
291 class Layout2,
292 class Accessor1,
293 class Accessor2>
294 inline void mat_sub_equal(
295 const std::mdspan<T, Extents1, Layout1, Accessor1> &inout,
296 const std::mdspan<T, Extents2, Layout2, Accessor2> &matb) {
297
298 SHAM_ASSERT(inout.extent(0) == inout.extent(0));
299 SHAM_ASSERT(inout.extent(1) == inout.extent(1));
300
301 for (int i = 0; i < inout.extent(0); i++) {
302 for (int j = 0; j < inout.extent(1); j++) {
303 inout(i, j) -= matb(i, j);
304 }
305 }
306 }
307
326 template<
327 class Ta,
328 class Tb,
329 class Extents1,
330 class Extents2,
331 class Extents3,
332 class Layout1,
333 class Layout2,
334 class Layout3,
335 class Accessor1,
336 class Accessor2,
337 class Accessor3>
338 inline void mat_prod(
339 const std::mdspan<Ta, Extents1, Layout1, Accessor1> &input1,
340 const std::mdspan<Ta, Extents2, Layout2, Accessor2> &input2,
341 const std::mdspan<Tb, Extents3, Layout3, Accessor3> &output) {
342
343 SHAM_ASSERT(input1.extent(0) == output.extent(0));
344 SHAM_ASSERT(input1.extent(1) == input2.extent(0));
345 SHAM_ASSERT(input2.extent(1) == output.extent(1));
346
347 // output_ij = mat1_ik mat2_jk
348 for (int i = 0; i < input1.extent(0); i++) {
349 for (int j = 0; j < input2.extent(1); j++) {
350 Tb sum = 0;
351 for (int k = 0; k < input1.extent(1); k++) {
352 sum += input1(i, k) * input2(k, j);
353 }
354 output(i, j) = sum;
355 }
356 }
357 }
358
372 template<class T, class SizeType, class Layout, class Accessor>
373 inline void mat_inv_33(
374 const std::mdspan<T, std::extents<SizeType, 3, 3>, Layout, Accessor> &input,
375 const std::mdspan<T, std::extents<SizeType, 3, 3>, Layout, Accessor> &output) {
376
377 T &a00 = input(0, 0);
378 T &a10 = input(1, 0);
379 T &a20 = input(2, 0);
380
381 T &a01 = input(0, 1);
382 T &a11 = input(1, 1);
383 T &a21 = input(2, 1);
384
385 T &a02 = input(0, 2);
386 T &a12 = input(1, 2);
387 T &a22 = input(2, 2);
388
389 T det
390 = (-a02 * a11 * a20 + a01 * a12 * a20 + a02 * a10 * a21 - a00 * a12 * a21
391 - a01 * a10 * a22 + a00 * a11 * a22);
392
393 output(0, 0) = (-a12 * a21 + a11 * a22) / det;
394 output(1, 0) = (a12 * a20 - a10 * a22) / det;
395 output(2, 0) = (-a11 * a20 + a10 * a21) / det;
396
397 output(0, 1) = (a02 * a21 - a01 * a22) / det;
398 output(1, 1) = (-a02 * a20 + a00 * a22) / det;
399 output(2, 1) = (a01 * a20 - a00 * a21) / det;
400
401 output(0, 2) = (-a02 * a11 + a01 * a12) / det;
402 output(1, 2) = (a02 * a10 - a00 * a12) / det;
403 output(2, 2) = (-a01 * a10 + a00 * a11) / det;
404 }
405
415 template<class T, class U, class Extents, class Layout, class Accessor>
416 inline void mat_L1_norm(const std::mdspan<T, Extents, Layout, Accessor> &input, U &res) {
417 res = 0;
418 for (auto i = 0; i < input.extent(0); i++) {
419 T sum = 0;
420 for (auto j = 0; j < input.extent(1); j++) {
421 sum += sham::abs(input(i, j));
422 }
423 res = sham::max(res, sum);
424 }
425 }
426
432 template<class T, class Extents, class Layout, class Accessor>
433 inline void mat_set_nul(const std::mdspan<T, Extents, Layout, Accessor> &input) {
434 mat_set_vals(input, [](auto i, auto j) -> T {
435 return 0;
436 });
437 }
438
444 template<class T, class Extents, class Layout, class Accessor>
445 inline void vec_set_nul(const std::mdspan<T, Extents, Layout, Accessor> &input) {
446 for (auto i = 0; i < input.extent(0); i++) {
447 input(i) = 0;
448 }
449 }
450
457 template<class T, class Extents, class Layout, class Accessor>
458 inline void vec_copy(
459 const std::mdspan<T, Extents, Layout, Accessor> &input,
460 const std::mdspan<T, Extents, Layout, Accessor> &output) {
461 SHAM_ASSERT(input.extent(0) == output.extent(0));
462
463 for (int i = 0; i < input.extent(0); i++) {
464 output(i) = input(i);
465 }
466 }
467
476 template<
477 class T,
478 class U,
479 class Extents1,
480 class Extents2,
481 class Layout1,
482 class Layout2,
483 class Accessor1,
484 class Accessor2>
485 inline void vec_axpy_beta(
486 const U alpha,
487 const std::mdspan<T, Extents1, Layout1, Accessor1> &input,
488 const U beta,
489 const std::mdspan<T, Extents2, Layout2, Accessor2> &output) {
490
491 SHAM_ASSERT(input.extent(0) == output.extent(0));
492
493 for (int i = 0; i < input.extent(0); i++) {
494 output(i) = alpha * input(i) + beta * output(i);
495 }
496 }
497
505 template<
506 class T,
507 class U,
508 class Extents1,
509 class Extents2,
510 class Layout1,
511 class Layout2,
512 class Accessor1,
513 class Accessor2>
514 inline void vec_axpy(
515 const U alpha,
516 const std::mdspan<T, Extents1, Layout1, Accessor1> &input,
517 const std::mdspan<T, Extents2, Layout2, Accessor2> &output) {
518
519 vec_axpy_beta(alpha, input, U{1}, output);
520 }
521
530 template<
531 class T,
532 class U,
533 class Extents1,
534 class Extents2,
535 class Layout1,
536 class Layout2,
537 class Accessor1,
538 class Accessor2>
539 inline void mat_axpy_beta(
540 const U alpha,
541 const std::mdspan<T, Extents1, Layout1, Accessor1> &input,
542 const U beta,
543 const std::mdspan<T, Extents2, Layout2, Accessor2> &output) {
544
545 SHAM_ASSERT(input.extent(0) == output.extent(0));
546 SHAM_ASSERT(input.extent(1) == output.extent(1));
547
548 for (int i = 0; i < input.extent(0); i++) {
549 for (int j = 0; j < input.extent(1); j++) {
550 output(i, j) = alpha * input(i, j) + beta * output(i, j);
551 }
552 }
553 }
554
562 template<
563 class T,
564 class U,
565 class Extents1,
566 class Extents2,
567 class Layout1,
568 class Layout2,
569 class Accessor1,
570 class Accessor2>
571 inline void mat_axpy(
572 const U alpha,
573 const std::mdspan<T, Extents1, Layout1, Accessor1> &input,
574 const std::mdspan<T, Extents2, Layout2, Accessor2> &output) {
575
576 mat_axpy_beta(alpha, input, U{1}, output);
577 }
578
588 template<
589 class T,
590 class U,
591 class Extents1,
592 class Extents2,
593 class Extents3,
594 class Layout1,
595 class Layout2,
596 class Layout3,
597 class Accessor1,
598 class Accessor2,
599 class Accessor3>
600 inline void mat_gemm(
601 const U alpha,
602 const std::mdspan<T, Extents1, Layout1, Accessor1> &input1,
603 const std::mdspan<T, Extents2, Layout2, Accessor2> &input2,
604 const U beta,
605 const std::mdspan<T, Extents3, Layout3, Accessor3> &output) {
606
607 SHAM_ASSERT(input1.extent(0) == output.extent(0));
608 SHAM_ASSERT(input1.extent(1) == input2.extent(0));
609 SHAM_ASSERT(input2.extent(1) == output.extent(1));
610
611 for (int i = 0; i < input1.extent(0); i++) {
612 for (int j = 0; j < input2.extent(1); j++) {
613 T sum = 0;
614 for (int k = 0; k < input1.extent(1); k++) {
615 sum += input1(i, k) * input2(k, j);
616 }
617 output(i, j) = alpha * sum + beta * output(i, j);
618 }
619 }
620 }
621
630
631 template<class T, class U, class Extents1, class Layout1, class Accessor1>
633 const std::mdspan<T, Extents1, Layout1, Accessor1> &inout, const U beta) {
634 for (int i = 0; i < inout.extent(0); i++) {
635 inout(i, i) = inout(i, i) + beta;
636 }
637 }
638
647 template<
648 class T,
649 class U,
650 class Extents1,
651 class Extents2,
652 class Extents3,
653 class Layout1,
654 class Layout2,
655 class Layout3,
656 class Accessor1,
657 class Accessor2,
658 class Accessor3>
659 inline void mat_gemv(
660 const U alpha,
661 const std::mdspan<T, Extents1, Layout1, Accessor1> &M,
662 const std::mdspan<T, Extents2, Layout2, Accessor2> &x,
663 const U beta,
664 const std::mdspan<T, Extents3, Layout3, Accessor3> &y) {
665
666 SHAM_ASSERT(M.extent(1) == x.extent(0));
667 SHAM_ASSERT(M.extent(0) == y.extent(0));
668
669 for (int i = 0; i < M.extent(0); i++) {
670 T sum = 0;
671 for (int j = 0; j < M.extent(1); j++) {
672 sum += M(i, j) * x(j);
673 }
674 y(i) = alpha * sum + beta * y(i);
675 }
676 }
677
683 template<
684 class T,
685 class Extents1,
686 class Extents2,
687 class Layout1,
688 class Layout2,
689 class Accessor1,
690 class Accessor2>
691 inline void mat_transpose(
692 const std::mdspan<T, Extents1, Layout1, Accessor1> &input,
693 const std::mdspan<T, Extents2, Layout2, Accessor2> &output) {
694
695 SHAM_ASSERT(input.extent(0) == output.extent(1));
696 SHAM_ASSERT(input.extent(1) == output.extent(0));
697
698 for (int i = 0; i < output.extent(0); i++) {
699 for (int j = 0; j < output.extent(1); j++) {
700 output(i, j) = input(j, i);
701 }
702 }
703 }
704
715 template<
716 class T,
717 class Extents1,
718 class Extents2,
719 class Layout1,
720 class Layout2,
721 class Accessor1,
722 class Accessor2>
723 inline void Cholesky_decomp(
724 const std::mdspan<T, Extents1, Layout1, Accessor1> &M,
725 const std::mdspan<T, Extents2, Layout2, Accessor2> &L) {
726
727 SHAM_ASSERT(M.extent(1) == M.extent(0));
728 SHAM_ASSERT(M.extent(0) == L.extent(0));
729 SHAM_ASSERT(L.extent(1) == L.extent(0));
730
731 for (int i = 0; i < M.extent(0); i++) {
732 T sum_ik = 0.0;
733 for (int k = 0; k < i; k++) {
734 sum_ik += L(i, k) * L(i, k);
735 }
736 L(i, i) = sycl::sqrt(M(i, i) - sum_ik);
737 for (int j = i + 1; j < M.extent(1); j++) {
738 T sum_ikjk = 0.0;
739 for (int k = 0; k < i; k++) {
740 sum_ikjk += L(i, k) * L(j, k);
741 }
742 L(j, i) = (M(i, j) - sum_ikjk) / L(i, i);
743 L(i, j) = 0.0;
744 }
745 }
746 }
747
759 template<
760 class T,
761 class Extents1,
762 class Extents2,
763 class Extents3,
764 class Layout1,
765 class Layout2,
766 class Layout3,
767 class Accessor1,
768 class Accessor2,
769 class Accessor3>
770 inline void Cholesky_solve(
771 const std::mdspan<T, Extents1, Layout1, Accessor1> &M,
772 const std::mdspan<T, Extents2, Layout2, Accessor2> &y,
773 const std::mdspan<T, Extents3, Layout3, Accessor3> &x) {
774
775 SHAM_ASSERT(M.extent(1) == M.extent(0));
776 SHAM_ASSERT(M.extent(1) == x.extent(0));
777 SHAM_ASSERT(M.extent(0) == y.extent(0));
778
779 std::vector<T> a(M.extent(0));
780 std::vector<T> L_storage(M.extent(0) * M.extent(1));
781
782 std::mdspan<T, Extents1> L{L_storage.data(), M.extent(0), M.extent(1)};
783 Cholesky_decomp(M, L);
784
785 for (int i = 0; i < M.extent(0); i++) {
786 T sum = 0.0;
787 for (int k = 0; k < i; k++) {
788 sum += L(i, k) * a[k];
789 }
790 a[i] = (y(i) - sum) / L(i, i);
791 }
792 for (int i = M.extent(0) - 1; i >= 0; i--) {
793 T sum = 0.0;
794 for (int k = i + 1; k < M.extent(0); k++) {
795 sum += L(k, i) * x(k);
796 }
797 x(i) = (a[i] - sum) / L(i, i);
798 }
799 }
800
801} // namespace shammath
Shamrock assertion utility.
#define SHAM_ASSERT(x)
Shorthand for SHAM_ASSERT_NAMED without a message.
Definition assert.hpp:67
constexpr void check_functor_signature(Func &&func)
Check if a callable object has the correct deduced signature.
namespace for math utility
Definition AABB.hpp:26
void vec_axpy(const U alpha, const std::mdspan< T, Extents1, Layout1, Accessor1 > &input, const std::mdspan< T, Extents2, Layout2, Accessor2 > &output)
This function compute y = alpha*x + y with x,y both vectors.
void mat_plus(const std::mdspan< T, Extents1, Layout1, Accessor1 > &input1, const std::mdspan< T, Extents2, Layout2, Accessor2 > &input2, const std::mdspan< T, Extents3, Layout3, Accessor3 > &output)
Add two matrices element-wise.
void mat_mul_scalar(const std::mdspan< T, Extents, Layout, Accessor > &input, const T &scalar)
Multiply a matrix by a scalar value.
void vec_set_vals(const std::mdspan< T, Extents, Layout, Accessor > &input, Func &&func)
Set the elements of a vector according to a user-provided function.
Definition matrix_op.hpp:68
void vec_axpy_beta(const U alpha, const std::mdspan< T, Extents1, Layout1, Accessor1 > &input, const U beta, const std::mdspan< T, Extents2, Layout2, Accessor2 > &output)
This function compute y = alpha*x + beta*y with x,y both vectors.
void mat_gemm(const U alpha, const std::mdspan< T, Extents1, Layout1, Accessor1 > &input1, const std::mdspan< T, Extents2, Layout2, Accessor2 > &input2, const U beta, const std::mdspan< T, Extents3, Layout3, Accessor3 > &output)
This function compute C = alpha*A*B + beta*C with A,B,C are matrices.
void mat_transpose(const std::mdspan< T, Extents1, Layout1, Accessor1 > &input, const std::mdspan< T, Extents2, Layout2, Accessor2 > &output)
This function transposes a matrix.
void vec_copy(const std::mdspan< T, Extents, Layout, Accessor > &input, const std::mdspan< T, Extents, Layout, Accessor > &output)
Copy the content of one vector in another.
void mat_L1_norm(const std::mdspan< T, Extents, Layout, Accessor > &input, U &res)
compute the L1 norm of a given matrix
void mat_set_nul(const std::mdspan< T, Extents, Layout, Accessor > &input)
Set the content of a matrix to zero.
void mat_set_vals(const std::mdspan< T, Extents, Layout, Accessor > &input, Func &&func)
Set the elements of a matrix according to a user-provided function.
Definition matrix_op.hpp:45
void mat_inv_33(const std::mdspan< T, std::extents< SizeType, 3, 3 >, Layout, Accessor > &input, const std::mdspan< T, std::extents< SizeType, 3, 3 >, Layout, Accessor > &output)
Compute the inverse of a 3x3 matrix.
void Cholesky_decomp(const std::mdspan< T, Extents1, Layout1, Accessor1 > &M, const std::mdspan< T, Extents2, Layout2, Accessor2 > &L)
This function performs Cholesky decomposition. From a (real) symmetric, definite-positive square matr...
void Cholesky_solve(const std::mdspan< T, Extents1, Layout1, Accessor1 > &M, const std::mdspan< T, Extents2, Layout2, Accessor2 > &y, const std::mdspan< T, Extents3, Layout3, Accessor3 > &x)
This function solves a system of linear equations with Cholesky decomposition. The system must have t...
void mat_axpy_beta(const U alpha, const std::mdspan< T, Extents1, Layout1, Accessor1 > &input, const U beta, const std::mdspan< T, Extents2, Layout2, Accessor2 > &output)
This function compute M = alpha*N + beta*M with M,N both matrices.
void mat_plus_equal_scalar_id(const std::mdspan< T, Extents1, Layout1, Accessor1 > &inout, const U beta)
This function compute addition of a matrix with mutiple of identity matrix A +=beta * I,...
void mat_plus_equal(const std::mdspan< T, Extents1, Layout1, Accessor1 > &inout, const std::mdspan< T, Extents2, Layout2, Accessor2 > &matb)
Add a matrix to another matrix element-wise and store the result in the first matrix.
void mat_sub_equal(const std::mdspan< T, Extents1, Layout1, Accessor1 > &inout, const std::mdspan< T, Extents2, Layout2, Accessor2 > &matb)
Subtract a matrix from another matrix element-wise and store the result in the first matrix.
void mat_axpy(const U alpha, const std::mdspan< T, Extents1, Layout1, Accessor1 > &input, const std::mdspan< T, Extents2, Layout2, Accessor2 > &output)
This function compute M = alpha*N + beta*M with M,N both matrices.
void mat_copy(const std::mdspan< T, Extents, Layout, Accessor > &input, const std::mdspan< T, Extents, Layout, Accessor > &output)
Copy a matrix to another matrix.
void vec_set_nul(const std::mdspan< T, Extents, Layout, Accessor > &input)
Set the content of a vector to zero.
void mat_set_identity(const std::mdspan< T, Extents, Layout, Accessor > &input1)
Set the content of a matrix to the identity matrix.
void mat_prod(const std::mdspan< Ta, Extents1, Layout1, Accessor1 > &input1, const std::mdspan< Ta, Extents2, Layout2, Accessor2 > &input2, const std::mdspan< Tb, Extents3, Layout3, Accessor3 > &output)
Compute the product of two matrices.
void mat_sub(const std::mdspan< T, Extents1, Layout1, Accessor1 > &input1, const std::mdspan< T, Extents2, Layout2, Accessor2 > &input2, const std::mdspan< T, Extents3, Layout3, Accessor3 > &output)
Subtract two matrices element-wise.
void mat_update_vals(const std::mdspan< T, Extents, Layout, Accessor > &input, Func &&func)
Update the elements of a matrix according to a user-provided function.
Definition matrix_op.hpp:91
void mat_gemv(const U alpha, const std::mdspan< T, Extents1, Layout1, Accessor1 > &M, const std::mdspan< T, Extents2, Layout2, Accessor2 > &x, const U beta, const std::mdspan< T, Extents3, Layout3, Accessor3 > &y)
This function performs matrix-vector multiplication as y = a*Mx + b*y.
Traits for C++ types.