<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2023-01-13" />
  <title>A free function linear algebra interface based on the BLAS</title>
  <style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
  <style>
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ background-color: #f6f8fa; }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span { } 
code span.al { color: #ff0000; } 
code span.an { } 
code span.at { } 
code span.bn { color: #9f6807; } 
code span.bu { color: #9f6807; } 
code span.cf { color: #00607c; } 
code span.ch { color: #9f6807; } 
code span.cn { } 
code span.co { color: #008000; font-style: italic; } 
code span.cv { color: #008000; font-style: italic; } 
code span.do { color: #008000; } 
code span.dt { color: #00607c; } 
code span.dv { color: #9f6807; } 
code span.er { color: #ff0000; font-weight: bold; } 
code span.ex { } 
code span.fl { color: #9f6807; } 
code span.fu { } 
code span.im { } 
code span.in { color: #008000; } 
code span.kw { color: #00607c; } 
code span.op { color: #af1915; } 
code span.ot { } 
code span.pp { color: #6f4e37; } 
code span.re { } 
code span.sc { color: #9f6807; } 
code span.ss { color: #9f6807; } 
code span.st { color: #9f6807; } 
code span.va { } 
code span.vs { color: #9f6807; } 
code span.wa { color: #008000; font-weight: bold; } 
code.diff {color: #898887}
code.diff span.va {color: #6.0e28}
code.diff span.st {color: #bf0303}
</style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

a.index:target {
display: inline;
}
.indexitems {
margin-left: 2em;
text-indent: -2em;
}
div.itemdescr {
margin-left: 3em;
}
.bnf {
font-family: serif;
margin-left: 40pt;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ncbnf {
font-family: serif;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
}
.ncsimplebnf {
font-family: serif;
font-style: italic;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
background: inherit; 
}
span.textnormal {
font-style: normal;
font-family: serif;
white-space: normal;
display: inline-block;
}
span.rlap {
display: inline-block;
width: 0px;
}
span.descr { font-style: normal; font-family: serif; }
span.grammarterm { font-style: italic; }
span.term { font-style: italic; }
span.terminal { font-family: monospace; font-style: normal; }
span.nonterminal { font-style: italic; }
span.tcode { font-family: monospace; font-style: normal; }
span.textbf { font-weight: bold; }
span.textsc { font-variant: small-caps; }
a.nontermdef { font-style: italic; font-family: serif; }
span.emph { font-style: italic; }
span.techterm { font-style: italic; }
span.mathit { font-style: italic; }
span.mathsf { font-family: sans-serif; }
span.mathrm { font-family: serif; font-style: normal; }
span.textrm { font-family: serif; }
span.textsl { font-style: italic; }
span.mathtt { font-family: monospace; font-style: normal; }
span.mbox { font-family: serif; font-style: normal; }
span.ungap { display: inline-block; width: 2pt; }
span.textit { font-style: italic; }
span.texttt { font-family: monospace; }
span.tcode_in_codeblock { font-family: monospace; font-style: normal; }
span.phantom { color: white; }

span.math { font-style: normal; }
span.mathblock {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 1.2em;
margin-bottom: 1.2em;
text-align: center;
}
span.mathalpha {
font-style: italic;
}
span.synopsis {
font-weight: bold;
margin-top: 0.5em;
display: block;
}
span.definition {
font-weight: bold;
display: block;
}
.codeblock {
margin-left: 1.2em;
line-height: 127%;
}
.outputblock {
margin-left: 1.2em;
line-height: 127%;
}
div.itemdecl {
margin-top: 2ex;
}
code.itemdeclcode {
white-space: pre;
display: block;
}
span.textsuperscript {
vertical-align: super;
font-size: smaller;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: smaller; line-height: 0; }
.footnote {
font-size: small;
margin-left: 2em;
margin-right: 2em;
margin-top: 0.6em;
margin-bottom: 0.6em;
}
div.minipage {
display: inline-block;
margin-right: 3em;
}
div.numberedTable {
text-align: center;
margin: 2em;
}
div.figure {
text-align: center;
margin: 2em;
}
table {
border: 1px solid black;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
margin-top: 0.8em;
text-align: left;
hyphens: none; 
}
td, th {
padding-left: 1em;
padding-right: 1em;
vertical-align: top;
}
td.empty {
padding: 0px;
padding-left: 1px;
}
td.left {
text-align: left;
}
td.right {
text-align: right;
}
td.center {
text-align: center;
}
td.justify {
text-align: justify;
}
td.border {
border-left: 1px solid black;
}
tr.rowsep, td.cline {
border-top: 1px solid black;
}
tr.even, tr.odd {
border-bottom: 1px solid black;
}
tr.capsep {
border-top: 3px solid black;
border-top-style: double;
}
tr.header {
border-bottom: 3px solid black;
border-bottom-style: double;
}
th {
border-bottom: 1px solid black;
}
span.centry {
font-weight: bold;
}
div.table {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
width: 90%;
}
span.indented {
display: block;
margin-left: 2em;
margin-bottom: 1em;
margin-top: 1em;
}
ol.enumeratea { list-style-type: none; background: inherit; }
ol.enumerate { list-style-type: none; background: inherit; }

code.sourceCode > span { display: inline; }

div#refs p { padding-left: 32px; text-indent: -32px; }
</style>
  <link href="data:image/vnd.microsoft.icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
  
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">A free function linear
algebra interface based on the BLAS</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #: </td>
    <td>P1673</td>
  </tr>
  <tr>
    <td>Date: </td>
    <td>2023-01-13</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project: </td>
    <td>Programming Language C++<br>
      LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to: </td>
    <td>
      Mark Hoemmen<br>&lt;<a href="mailto:mhoemmen@nvidia.com" class="email">mhoemmen@nvidia.com</a>&gt;<br>
      Daisy Hollman<br>&lt;<a href="mailto:cpp@dsh.fyi" class="email">cpp@dsh.fyi</a>&gt;<br>
      Christian Trott<br>&lt;<a href="mailto:crtrott@sandia.gov" class="email">crtrott@sandia.gov</a>&gt;<br>
      Daniel Sunderland<br>&lt;<a href="mailto:dansunderland@gmail.com" class="email">dansunderland@gmail.com</a>&gt;<br>
      Nevin Liber<br>&lt;<a href="mailto:nliber@anl.gov" class="email">nliber@anl.gov</a>&gt;<br>
      Alicia Klinvex<br>&lt;<a href="mailto:alicia.klinvex@unnpp.gov" class="email">alicia.klinvex@unnpp.gov</a>&gt;<br>
      Li-Ta Lo<br>&lt;<a href="mailto:ollie@lanl.gov" class="email">ollie@lanl.gov</a>&gt;<br>
      Damien Lebrun-Grandie<br>&lt;<a href="mailto:lebrungrandt@ornl.gov" class="email">lebrungrandt@ornl.gov</a>&gt;<br>
      Graham Lopez<br>&lt;<a href="mailto:glopez@nvidia.com" class="email">glopez@nvidia.com</a>&gt;<br>
      Peter Caday<br>&lt;<a href="mailto:peter.caday@intel.com" class="email">peter.caday@intel.com</a>&gt;<br>
      Sarah Knepper<br>&lt;<a href="mailto:sarah.knepper@intel.com" class="email">sarah.knepper@intel.com</a>&gt;<br>
      Piotr Luszczek<br>&lt;<a href="mailto:luszczek@icl.utk.edu" class="email">luszczek@icl.utk.edu</a>&gt;<br>
      Timothy Costa<br>&lt;<a href="mailto:tcosta@nvidia.com" class="email">tcosta@nvidia.com</a>&gt;<br>
    </td>
  </tr>
</table>

</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#authors-and-contributors" id="toc-authors-and-contributors"><span class="toc-section-number">1</span> Authors and contributors</a>
<ul>
<li><a href="#authors" id="toc-authors"><span class="toc-section-number">1.1</span> Authors</a></li>
<li><a href="#contributors" id="toc-contributors"><span class="toc-section-number">1.2</span> Contributors</a></li>
</ul></li>
<li><a href="#revision-history" id="toc-revision-history"><span class="toc-section-number">2</span> Revision history</a></li>
<li><a href="#purpose-of-this-paper" id="toc-purpose-of-this-paper"><span class="toc-section-number">3</span>
Purpose of this paper</a></li>
<li><a href="#overview-of-contents" id="toc-overview-of-contents"><span class="toc-section-number">4</span> Overview of contents</a></li>
<li><a href="#interoperable-with-other-linear-algebra-proposals" id="toc-interoperable-with-other-linear-algebra-proposals"><span class="toc-section-number">5</span> Interoperable with other linear
algebra proposals</a></li>
<li><a href="#why-include-dense-linear-algebra-in-the-c-standard-library" id="toc-why-include-dense-linear-algebra-in-the-c-standard-library"><span class="toc-section-number">6</span> Why include dense linear algebra in
the C++ Standard Library?</a></li>
<li><a href="#why-base-a-c-linear-algebra-library-on-the-blas" id="toc-why-base-a-c-linear-algebra-library-on-the-blas"><span class="toc-section-number">7</span> Why base a C++ linear algebra
library on the BLAS?</a></li>
<li><a href="#criteria-for-including-algorithms" id="toc-criteria-for-including-algorithms"><span class="toc-section-number">8</span> Criteria for including
algorithms</a>
<ul>
<li><a href="#criteria-for-all-the-algorithms" id="toc-criteria-for-all-the-algorithms"><span class="toc-section-number">8.1</span> Criteria for all the
algorithms</a></li>
<li><a href="#criteria-for-including-blas-1-algorithms-coexistence-with-ranges" id="toc-criteria-for-including-blas-1-algorithms-coexistence-with-ranges"><span class="toc-section-number">8.2</span> Criteria for including BLAS 1
algorithms; coexistence with ranges</a>
<ul>
<li><a href="#low-risk-of-synactic-collision-with-ranges" id="toc-low-risk-of-synactic-collision-with-ranges"><span class="toc-section-number">8.2.1</span> Low risk of synactic collision
with ranges</a></li>
<li><a href="#minimal-overlap-with-ranges-is-justified-by-user-convenience" id="toc-minimal-overlap-with-ranges-is-justified-by-user-convenience"><span class="toc-section-number">8.2.2</span> Minimal overlap with ranges is
justified by user convenience</a></li>
</ul></li>
</ul></li>
<li><a href="#notation-and-conventions" id="toc-notation-and-conventions"><span class="toc-section-number">9</span> Notation and conventions</a>
<ul>
<li><a href="#the-blas-uses-fortran-terms" id="toc-the-blas-uses-fortran-terms"><span class="toc-section-number">9.1</span> The BLAS uses Fortran
terms</a></li>
<li><a href="#we-call-subroutines-functions" id="toc-we-call-subroutines-functions"><span class="toc-section-number">9.2</span> We call “subroutines”
functions</a></li>
<li><a href="#element-types-and-blas-function-name-prefix" id="toc-element-types-and-blas-function-name-prefix"><span class="toc-section-number">9.3</span> Element types and BLAS function
name prefix</a></li>
</ul></li>
<li><a href="#what-we-exclude-from-the-design" id="toc-what-we-exclude-from-the-design"><span class="toc-section-number">10</span> What we exclude from the design</a>
<ul>
<li><a href="#most-functions-not-in-the-reference-blas" id="toc-most-functions-not-in-the-reference-blas"><span class="toc-section-number">10.1</span> Most functions not in the
Reference BLAS</a></li>
<li><a href="#lapack-or-related-functionality" id="toc-lapack-or-related-functionality"><span class="toc-section-number">10.2</span> LAPACK or related
functionality</a></li>
<li><a href="#extended-precision-blas" id="toc-extended-precision-blas"><span class="toc-section-number">10.3</span> Extended-precision BLAS</a></li>
<li><a href="#arithmetic-operators-and-associated-expression-templates" id="toc-arithmetic-operators-and-associated-expression-templates"><span class="toc-section-number">10.4</span> Arithmetic operators and
associated expression templates</a></li>
<li><a href="#banded-matrix-layouts" id="toc-banded-matrix-layouts"><span class="toc-section-number">10.5</span> Banded matrix layouts</a></li>
<li><a href="#tensors" id="toc-tensors"><span class="toc-section-number">10.6</span> Tensors</a></li>
<li><a href="#explicit-support-for-asynchronous-return-of-scalar-values" id="toc-explicit-support-for-asynchronous-return-of-scalar-values"><span class="toc-section-number">10.7</span> Explicit support for asynchronous
return of scalar values</a></li>
</ul></li>
<li><a href="#design-justification" id="toc-design-justification"><span class="toc-section-number">11</span> Design justification</a>
<ul>
<li><a href="#we-do-not-require-using-the-blas-library-or-any-particular-back-end" id="toc-we-do-not-require-using-the-blas-library-or-any-particular-back-end"><span class="toc-section-number">11.1</span> We do not require using the BLAS
library or any particular “back-end”</a></li>
<li><a href="#why-use-mdspan" id="toc-why-use-mdspan"><span class="toc-section-number">11.2</span> Why use <code>mdspan</code>?</a>
<ul>
<li><a href="#view-of-a-multidimensional-array" id="toc-view-of-a-multidimensional-array"><span class="toc-section-number">11.2.1</span> View of a multidimensional
array</a></li>
<li><a href="#ease-of-use" id="toc-ease-of-use"><span class="toc-section-number">11.2.2</span> Ease of use</a></li>
<li><a href="#blas-and-mdspan-are-low-level" id="toc-blas-and-mdspan-are-low-level"><span class="toc-section-number">11.2.3</span> BLAS and <code>mdspan</code>
are low level</a></li>
<li><a href="#hook-for-future-expansion" id="toc-hook-for-future-expansion"><span class="toc-section-number">11.2.4</span> Hook for future
expansion</a></li>
<li><a href="#generic-enough-to-replace-a-multidimensional-array-concept" id="toc-generic-enough-to-replace-a-multidimensional-array-concept"><span class="toc-section-number">11.2.5</span> Generic enough to replace a
“multidimensional array concept”</a></li>
</ul></li>
<li><a href="#function-argument-aliasing-and-zero-scalar-multipliers" id="toc-function-argument-aliasing-and-zero-scalar-multipliers"><span class="toc-section-number">11.3</span> Function argument aliasing and
zero scalar multipliers</a></li>
<li><a href="#support-for-different-matrix-layouts" id="toc-support-for-different-matrix-layouts"><span class="toc-section-number">11.4</span> Support for different matrix
layouts</a></li>
<li><a href="#interpretation-of-lower-upper-triangular" id="toc-interpretation-of-lower-upper-triangular"><span class="toc-section-number">11.5</span> Interpretation of “lower / upper
triangular”</a>
<ul>
<li><a href="#triangle-refers-to-what-part-of-the-matrix-is-accessed" id="toc-triangle-refers-to-what-part-of-the-matrix-is-accessed"><span class="toc-section-number">11.5.1</span> Triangle refers to what part of
the matrix is accessed</a></li>
<li><a href="#blas-applies-uplo-to-original-matrix-we-apply-triangle-to-transformed-matrix" id="toc-blas-applies-uplo-to-original-matrix-we-apply-triangle-to-transformed-matrix"><span class="toc-section-number">11.5.2</span> BLAS applies UPLO to original
matrix; we apply Triangle to transformed matrix</a></li>
<li><a href="#summary" id="toc-summary"><span class="toc-section-number">11.5.3</span> Summary</a></li>
</ul></li>
<li><a href="#over--and-underflow-wording-for-vector-2-norm" id="toc-over--and-underflow-wording-for-vector-2-norm"><span class="toc-section-number">11.6</span> Over- and underflow wording for
vector 2-norm</a></li>
<li><a href="#constraining-matrix-and-vector-element-types-and-scalars" id="toc-constraining-matrix-and-vector-element-types-and-scalars"><span class="toc-section-number">11.7</span> Constraining matrix and vector
element types and scalars</a>
<ul>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">11.7.1</span> Introduction</a></li>
<li><a href="#value-type-constraints-do-not-suffice-to-describe-algorithm-behavior" id="toc-value-type-constraints-do-not-suffice-to-describe-algorithm-behavior"><span class="toc-section-number">11.7.2</span> Value type constraints do not
suffice to describe algorithm behavior</a></li>
<li><a href="#associativity-is-too-strict" id="toc-associativity-is-too-strict"><span class="toc-section-number">11.7.3</span> Associativity is too
strict</a></li>
<li><a href="#generalizing-associativity-helps-little" id="toc-generalizing-associativity-helps-little"><span class="toc-section-number">11.7.4</span> Generalizing associativity
helps little</a></li>
<li><a href="#categories-of-qoi-enhancements" id="toc-categories-of-qoi-enhancements"><span class="toc-section-number">11.7.5</span> Categories of QoI
enhancements</a></li>
<li><a href="#properties-of-textbook-algorithm-descriptions" id="toc-properties-of-textbook-algorithm-descriptions"><span class="toc-section-number">11.7.6</span> Properties of textbook
algorithm descriptions</a></li>
<li><a href="#reordering-sums-and-creating-temporaries" id="toc-reordering-sums-and-creating-temporaries"><span class="toc-section-number">11.7.7</span> Reordering sums and creating
temporaries</a></li>
<li><a href="#textbook-algorithm-description-in-semiring-terms" id="toc-textbook-algorithm-description-in-semiring-terms"><span class="toc-section-number">11.7.8</span> “Textbook” algorithm
description in semiring terms</a></li>
<li><a href="#summary-1" id="toc-summary-1"><span class="toc-section-number">11.7.9</span> Summary</a></li>
</ul></li>
<li><a href="#support-for-user-defined-complex-number-types" id="toc-support-for-user-defined-complex-number-types"><span class="toc-section-number">11.8</span> Support for user-defined complex
number types</a>
<ul>
<li><a href="#conj-does-not-have-the-desired-interface" id="toc-conj-does-not-have-the-desired-interface"><span class="toc-section-number">11.8.1</span> <code>conj</code> does not have
the desired interface</a></li>
<li><a href="#why-users-define-their-own-complex-number-types" id="toc-why-users-define-their-own-complex-number-types"><span class="toc-section-number">11.8.2</span> Why users define their own
complex number types</a></li>
<li><a href="#why-users-want-to-conjugate-matrices-of-real-numbers" id="toc-why-users-want-to-conjugate-matrices-of-real-numbers"><span class="toc-section-number">11.8.3</span> Why users want to “conjugate”
matrices of real numbers</a></li>
<li><a href="#effects-of-conjs-real-to-complex-change" id="toc-effects-of-conjs-real-to-complex-change"><span class="toc-section-number">11.8.4</span> Effects of <code>conj</code>’s
real-to-complex change</a></li>
<li><a href="#lewg-feedback-on-r8-solution" id="toc-lewg-feedback-on-r8-solution"><span class="toc-section-number">11.8.5</span> LEWG feedback on R8
solution</a></li>
<li><a href="#sg6s-response-to-lewgs-r8-feedback" id="toc-sg6s-response-to-lewgs-r8-feedback"><span class="toc-section-number">11.8.6</span> SG6’s response to LEWG’s R8
feedback</a></li>
<li><a href="#current-solution" id="toc-current-solution"><span class="toc-section-number">11.8.7</span> Current solution</a></li>
</ul></li>
<li><a href="#support-for-division-with-noncommutative-multiplication" id="toc-support-for-division-with-noncommutative-multiplication"><span class="toc-section-number">11.9</span> Support for division with
noncommutative multiplication</a></li>
</ul></li>
<li><a href="#future-work" id="toc-future-work"><span class="toc-section-number">12</span> Future work</a>
<ul>
<li><a href="#generalize-function-parameters" id="toc-generalize-function-parameters"><span class="toc-section-number">12.1</span> Generalize function
parameters</a></li>
<li><a href="#batched-linear-algebra" id="toc-batched-linear-algebra"><span class="toc-section-number">12.2</span> Batched linear algebra</a></li>
</ul></li>
<li><a href="#data-structures-and-utilities-borrowed-from-other-proposals" id="toc-data-structures-and-utilities-borrowed-from-other-proposals"><span class="toc-section-number">13</span> Data structures and utilities
borrowed from other proposals</a>
<ul>
<li><a href="#mdspan" id="toc-mdspan"><span class="toc-section-number">13.1</span> <code>mdspan</code></a></li>
<li><a href="#new-mdspan-layouts-in-this-proposal" id="toc-new-mdspan-layouts-in-this-proposal"><span class="toc-section-number">13.2</span> New <code>mdspan</code> layouts
in this proposal</a></li>
</ul></li>
<li><a href="#acknowledgments" id="toc-acknowledgments"><span class="toc-section-number">14</span> Acknowledgments</a></li>
<li><a href="#references" id="toc-references"><span class="toc-section-number">15</span> References</a>
<ul>
<li><a href="#references-by-coathors" id="toc-references-by-coathors"><span class="toc-section-number">15.1</span> References by coathors</a></li>
<li><a href="#other-references" id="toc-other-references"><span class="toc-section-number">15.2</span> Other references</a></li>
</ul></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">16</span> Wording</a>
<ul>
<li><a href="#add-subsection-28.9-linalg-with-the-following" id="toc-add-subsection-28.9-linalg-with-the-following"><span class="toc-section-number">16.1</span> Add subsection 28.9 [linalg] with
the following</a></li>
<li><a href="#requirements-linalg.reqs" id="toc-requirements-linalg.reqs"><span class="toc-section-number">16.2</span> Requirements [linalg.reqs]</a>
<ul>
<li><a href="#value-and-reference-requirements-linalg.reqs.val" id="toc-value-and-reference-requirements-linalg.reqs.val"><span class="toc-section-number">16.2.1</span> Value and reference
requirements [linalg.reqs.val]</a></li>
<li><a href="#requirements-for-algorithms-and-methods-on-floating-point-values-linalg.reqs.flpt" id="toc-requirements-for-algorithms-and-methods-on-floating-point-values-linalg.reqs.flpt"><span class="toc-section-number">16.2.2</span> Requirements for algorithms and
methods on floating-point values [linalg.reqs.flpt]</a></li>
</ul></li>
<li><a href="#tag-classes-linalg.tags" id="toc-tag-classes-linalg.tags"><span class="toc-section-number">16.3</span> Tag classes [linalg.tags]</a>
<ul>
<li><a href="#storage-order-tags-linalg.tags.order" id="toc-storage-order-tags-linalg.tags.order"><span class="toc-section-number">16.3.1</span> Storage order tags
[linalg.tags.order]</a></li>
<li><a href="#triangle-tags-linalg.tags.triangle" id="toc-triangle-tags-linalg.tags.triangle"><span class="toc-section-number">16.3.2</span> Triangle tags
[linalg.tags.triangle]</a></li>
<li><a href="#diagonal-tags-linalg.tags.diagonal" id="toc-diagonal-tags-linalg.tags.diagonal"><span class="toc-section-number">16.3.3</span> Diagonal tags
[linalg.tags.diagonal]</a></li>
</ul></li>
<li><a href="#layouts-for-packed-matrix-types-linalg.layouts" id="toc-layouts-for-packed-matrix-types-linalg.layouts"><span class="toc-section-number">16.4</span> Layouts for packed matrix types
[linalg.layouts]</a>
<ul>
<li><a href="#layout_blas_packed-linalg.layouts.packed" id="toc-layout_blas_packed-linalg.layouts.packed"><span class="toc-section-number">16.4.1</span> <code>layout_blas_packed</code>
[linalg.layouts.packed]</a></li>
</ul></li>
<li><a href="#scaled-in-place-transformation-linalg.scaled" id="toc-scaled-in-place-transformation-linalg.scaled"><span class="toc-section-number">16.5</span> Scaled in-place transformation
[linalg.scaled]</a>
<ul>
<li><a href="#exposition-only-function-object-conj-if-needed-linalg.scaled.conj" id="toc-exposition-only-function-object-conj-if-needed-linalg.scaled.conj"><span class="toc-section-number">16.5.1</span> Exposition-only function object
<em><code>conj-if-needed</code></em> [linalg.scaled.conj]</a></li>
<li><a href="#exposition-only-class-templates-proxy-reference-base-and-proxy-reference-linalg.scaled.base" id="toc-exposition-only-class-templates-proxy-reference-base-and-proxy-reference-linalg.scaled.base"><span class="toc-section-number">16.5.2</span> Exposition-only class templates
<em><code>proxy-reference-base</code></em> and
<em><code>proxy-reference</code></em> [linalg.scaled.base]</a></li>
<li><a href="#exposition-only-class-template-scaled-scalar" id="toc-exposition-only-class-template-scaled-scalar"><span class="toc-section-number">16.5.3</span> Exposition-only class template
<em><code>scaled-scalar</code></em></a></li>
<li><a href="#class-template-accessor_scaled-linalg.scaled.accessor_scaled" id="toc-class-template-accessor_scaled-linalg.scaled.accessor_scaled"><span class="toc-section-number">16.5.4</span> Class template
<code>accessor_scaled</code> [linalg.scaled.accessor_scaled]</a></li>
<li><a href="#scaled-linalg.scaled.scaled" id="toc-scaled-linalg.scaled.scaled"><span class="toc-section-number">16.5.5</span> <code>scaled</code>
[linalg.scaled.scaled]</a></li>
</ul></li>
<li><a href="#conjugated-in-place-transformation-linalg.conj" id="toc-conjugated-in-place-transformation-linalg.conj"><span class="toc-section-number">16.6</span> Conjugated in-place
transformation [linalg.conj]</a>
<ul>
<li><a href="#exposition-only-class-template-conjugated-scalar" id="toc-exposition-only-class-template-conjugated-scalar"><span class="toc-section-number">16.6.1</span> Exposition-only class template
<em><code>conjugated-scalar</code></em></a></li>
<li><a href="#class-template-accessor_conjugate-linalg.conj.accessor_conjugate" id="toc-class-template-accessor_conjugate-linalg.conj.accessor_conjugate"><span class="toc-section-number">16.6.2</span> Class template
<code>accessor_conjugate</code>
[linalg.conj.accessor_conjugate]</a></li>
<li><a href="#conjugated-linalg.conj.conjugated" id="toc-conjugated-linalg.conj.conjugated"><span class="toc-section-number">16.6.3</span> <code>conjugated</code>
[linalg.conj.conjugated]</a></li>
</ul></li>
<li><a href="#transpose-in-place-transformation-linalg.transp" id="toc-transpose-in-place-transformation-linalg.transp"><span class="toc-section-number">16.7</span> Transpose in-place transformation
[linalg.transp]</a>
<ul>
<li><a href="#layout_transpose-linalg.transp.layout_transpose" id="toc-layout_transpose-linalg.transp.layout_transpose"><span class="toc-section-number">16.7.1</span> <code>layout_transpose</code>
[linalg.transp.layout_transpose]</a></li>
<li><a href="#transposed-linalg.transp.transposed" id="toc-transposed-linalg.transp.transposed"><span class="toc-section-number">16.7.2</span> <code>transposed</code>
[linalg.transp.transposed]</a></li>
</ul></li>
<li><a href="#conjugate-transpose-transform-linalg.conj_transp" id="toc-conjugate-transpose-transform-linalg.conj_transp"><span class="toc-section-number">16.8</span> Conjugate transpose transform
[linalg.conj_transp]</a></li>
<li><a href="#exposition-only-concepts-and-traits-linalg.concepts" id="toc-exposition-only-concepts-and-traits-linalg.concepts"><span class="toc-section-number">16.9</span> Exposition-only concepts and
traits [linalg.concepts]</a></li>
<li><a href="#algorithms-linalg.algs" id="toc-algorithms-linalg.algs"><span class="toc-section-number">16.10</span> Algorithms [linalg.algs]</a>
<ul>
<li><a href="#requirements-based-on-template-parameter-name-linalg.algs.reqs" id="toc-requirements-based-on-template-parameter-name-linalg.algs.reqs"><span class="toc-section-number">16.10.1</span> Requirements based on template
parameter name [linalg.algs.reqs]</a></li>
<li><a href="#blas-1-functions-linalg.algs.blas1" id="toc-blas-1-functions-linalg.algs.blas1"><span class="toc-section-number">16.10.2</span> BLAS 1 functions
[linalg.algs.blas1]</a></li>
<li><a href="#blas-2-functions-linalg.algs.blas2" id="toc-blas-2-functions-linalg.algs.blas2"><span class="toc-section-number">16.10.3</span> BLAS 2 functions
[linalg.algs.blas2]</a></li>
<li><a href="#blas-3-functions-linalg.algs.blas3" id="toc-blas-3-functions-linalg.algs.blas3"><span class="toc-section-number">16.10.4</span> BLAS 3 functions
[linalg.algs.blas3]</a></li>
</ul></li>
</ul></li>
<li><a href="#examples" id="toc-examples"><span class="toc-section-number">17</span> Examples</a>
<ul>
<li><a href="#cholesky-factorization" id="toc-cholesky-factorization"><span class="toc-section-number">17.1</span> Cholesky factorization</a></li>
<li><a href="#solve-linear-system-using-cholesky-factorization" id="toc-solve-linear-system-using-cholesky-factorization"><span class="toc-section-number">17.2</span> Solve linear system using
Cholesky factorization</a></li>
<li><a href="#compute-qr-factorization-of-a-tall-skinny-matrix" id="toc-compute-qr-factorization-of-a-tall-skinny-matrix"><span class="toc-section-number">17.3</span> Compute QR factorization of a
tall skinny matrix</a></li>
</ul></li>
</ul>
</div>
<h1 data-number="1" id="authors-and-contributors"><span class="header-section-number">1</span> Authors and contributors<a href="#authors-and-contributors" class="self-link"></a></h1>
<h2 data-number="1.1" id="authors"><span class="header-section-number">1.1</span> Authors<a href="#authors" class="self-link"></a></h2>
<ul>
<li><p>Mark Hoemmen (mhoemmen@nvidia.com) (NVIDIA)</p></li>
<li><p>Daisy Hollman (cpp@dsh.fyi) (Google)</p></li>
<li><p>Christian Trott (crtrott@sandia.gov) (Sandia National
Laboratories)</p></li>
<li><p>Daniel Sunderland (dansunderland@gmail.com)</p></li>
<li><p>Nevin Liber (nliber@anl.gov) (Argonne National
Laboratory)</p></li>
<li><p>Alicia Klinvex (alicia.klinvex@unnpp.gov) (Naval Nuclear
Laboratory)</p></li>
<li><p>Li-Ta Lo (ollie@lanl.gov) (Los Alamos National
Laboratory)</p></li>
<li><p>Damien Lebrun-Grandie (lebrungrandt@ornl.gov) (Oak Ridge National
Laboratories)</p></li>
<li><p>Graham Lopez (glopez@nvidia.com) (NVIDIA)</p></li>
<li><p>Peter Caday (peter.caday@intel.com) (Intel)</p></li>
<li><p>Sarah Knepper (sarah.knepper@intel.com) (Intel)</p></li>
<li><p>Piotr Luszczek (luszczek@icl.utk.edu) (University of
Tennessee)</p></li>
<li><p>Timothy Costa (tcosta@nvidia.com) (NVIDIA)</p></li>
</ul>
<h2 data-number="1.2" id="contributors"><span class="header-section-number">1.2</span> Contributors<a href="#contributors" class="self-link"></a></h2>
<ul>
<li><p>Chip Freitag (chip.freitag@amd.com) (AMD)</p></li>
<li><p>Bryce Adelstein Lelbach (brycelelbach@gmail.com)
(NVIDIA)</p></li>
<li><p>Srinath Vadlamani (Srinath.Vadlamani@arm.com) (ARM)</p></li>
<li><p>Rene Vanoostrum (Rene.Vanoostrum@amd.com) (AMD)</p></li>
</ul>
<h1 data-number="2" id="revision-history"><span class="header-section-number">2</span> Revision history<a href="#revision-history" class="self-link"></a></h1>
<ul>
<li><p>Revision 0 (pre-Cologne) submitted 2019-06-17</p>
<ul>
<li>Received feedback in Cologne from SG6, LEWGI, and (???).</li>
</ul></li>
<li><p>Revision 1 (pre-Belfast) to be submitted 2019-10-07</p>
<ul>
<li><p>Account for Cologne 2019 feedback</p>
<ul>
<li><p>Make interface more consistent with existing Standard
algorithms</p></li>
<li><p>Change <code>dot</code>, <code>dotc</code>,
<code>vector_norm2</code>, and <code>vector_abs_sum</code> to imitate
<code>reduce</code>, so that they return their result, instead of taking
an output parameter. Users may set the result type via optional
<code>init</code> parameter.</p></li>
</ul></li>
<li><p>Minor changes to “expression template” classes, based on
implementation experience</p></li>
<li><p>Briefly address LEWGI request of exploring concepts for input
arguments.</p></li>
<li><p>Lazy ranges style API was NOT explored.</p></li>
</ul></li>
<li><p>Revision 2 (pre-Cologne) to be submitted 2020-01-13</p>
<ul>
<li><p>Add “Future work” section.</p></li>
<li><p>Remove “Options and votes” section (which were addressed in SG6,
SG14, and LEWGI).</p></li>
<li><p>Remove <code>basic_mdarray</code> overloads.</p></li>
<li><p>Remove batched linear algebra operations.</p></li>
<li><p>Remove over- and underflow requirement for
<code>vector_norm2</code>.</p></li>
<li><p><em>Mandate</em> any extent compatibility checks that can be done
at compile time.</p></li>
<li><p>Add missing functions
<code>{symmetric,hermitian}_matrix_rank_k_update</code> and
<code>triangular_matrix_{left,right}_product</code>.</p></li>
<li><p>Remove <code>packed_view</code> function.</p></li>
<li><p>Fix wording for
<code>{conjugate,transpose,conjugate_transpose}_view</code>, so that
implementations may optimize the return type. Make sure that
<code>transpose_view</code> of a <code>layout_blas_packed</code> matrix
returns a <code>layout_blas_packed</code> matrix with opposite
<code>Triangle</code> and <code>StorageOrder</code>.</p></li>
<li><p>Remove second template parameter <code>T</code> from
<code>accessor_conjugate</code>.</p></li>
<li><p>Make <code>scaled_scalar</code> and
<code>conjugated_scalar</code> exposition only.</p></li>
<li><p>Add in-place overloads of
<code>triangular_matrix_matrix_{left,right}_solve</code>,
<code>triangular_matrix_{left,right}_product</code>, and
<code>triangular_matrix_vector_solve</code>.</p></li>
<li><p>Add <code>alpha</code> overloads to
<code>{symmetric,hermitian}_matrix_rank_{1,k}_update</code>.</p></li>
<li><p>Add Cholesky factorization and solve examples.</p></li>
</ul></li>
<li><p>Revision 3 (electronic) to be submitted 2021-04-15</p>
<ul>
<li><p>Per LEWG request, add a section on our investigation of
constraining template parameters with concepts, in the manner of P1813R0
with the numeric algorithms. We concluded that we disagree with the
approach of P1813R0, and that the Standard’s current
<em>GENERALIZED_SUM</em> approach better expresses numeric algorithms’
behavior.</p></li>
<li><p>Update references to the current revision of P0009
(<code>mdspan</code>).</p></li>
<li><p>Per LEWG request, introduce <code>std::linalg</code> namespace
and put everything in there.</p></li>
<li><p>Per LEWG request, replace the <code>linalg_</code> prefix with
the aforementioned namespace. We renamed <code>linalg_add</code> to
<code>add</code>, <code>linalg_copy</code> to <code>copy</code>, and
<code>linalg_swap</code> to <code>swap_elements</code>.</p></li>
<li><p>Per LEWG request, do not use <code>_view</code> as a suffix, to
avoid confusion with “views” in the sense of Ranges. We renamed
<code>conjugate_view</code> to <code>conjugated</code>,
<code>conjugate_transpose_view</code> to
<code>conjugate_transposed</code>, <code>scaled_view</code> to
<code>scaled</code>, and <code>transpose_view</code> to
<code>transposed</code>.</p></li>
<li><p>Change wording from “then implementations will use
<code>T</code>’s precision or greater for intermediate terms in the
sum,” to “then intermediate terms in the sum use <code>T</code>’s
precision or greater.” Thanks to Jens Maurer for this suggestion (and
many others!).</p></li>
<li><p>Before, a Note on <code>vector_norm2</code> said, “We recommend
that implementers document their guarantees regarding overflow and
underflow of <code>vector_norm2</code> for floating-point return types.”
Implementations always document “implementation-defined behavior” per
<strong>[defs.impl.defined]</strong>. (Thanks to Jens Maurer for
pointing out that “We recommend…” does not belong in the Standard.)
Thus, we changed this from a Note to normative wording in Remarks: “If
either <code>in_vector_t::element_type</code> or <code>T</code> are
floating-point types or complex versions thereof, then any guarantees
regarding overflow and underflow of <code>vector_norm2</code> are
implementation-defined.”</p></li>
<li><p>Define return types of the <code>dot</code>, <code>dotc</code>,
<code>vector_norm2</code>, and <code>vector_abs_sum</code> overloads
with <code>auto</code> return type.</p></li>
<li><p>Remove the explicitly stated constraint on <code>add</code> and
<code>copy</code> that the rank of the array arguments be no more than
2. This is redundant, because we already impose this via the existing
constraints on template parameters named <code>in_object*_t</code>,
<code>inout_object*_t</code>, or <code>out_object*_t</code>. If we later
wish to relax this restriction, then we only have to do so in one
place.</p></li>
<li><p>Add <code>vector_sum_of_squares</code>. First, this gives
implementers a path to implementing <code>vector_norm2</code> in a way
that achieves the over/underflow guarantees intended by the BLAS
Standard. Second, this is a useful algorithm in itself for parallelizing
vector 2-norm computation.</p></li>
<li><p>Add <code>matrix_frob_norm</code>, <code>matrix_one_norm</code>,
and <code>matrix_inf_norm</code> (thanks to coauthor Piotr
Luszczek).</p></li>
<li><p>Address LEWG request for us to investigate support for GPU
memory. See section “Explicit support for asynchronous return of scalar
values.”</p></li>
<li><p>Add <code>ExecutionPolicy</code> overloads of the in-place
versions of <code>triangular_matrix_vector_solve</code>,
<code>triangular_matrix_left_product</code>,
<code>triangular_matrix_right_product</code>,
<code>triangular_matrix_matrix_left_solve</code>, and
<code>triangular_matrix_matrix_right_solve</code>.</p></li>
</ul></li>
<li><p>Revision 4 (electronic), to be submitted 2021-08-15</p>
<ul>
<li><p>Update authors’ contact info.</p></li>
<li><p>Rebase atop P2299R3, which in turn sits atop P0009R12. Make any
needed fixes due to these changes. (P1673R3 was based on P0009R10,
without P2299.) Update P0009 references to point to the latest version
(R12).</p></li>
<li><p>Fix requirements for
<code>{symmetric,hermitian}_matrix_{left,right}_product</code>.</p></li>
<li><p>Change <code>SemiRegular&lt;Scalar&gt;</code> to
<code>semiregular&lt;Scalar&gt;</code>.</p></li>
<li><p>Make <code>Real</code> requirements refer to
<strong>[complex.numbers.general]</strong>, rather than explicitly
listing allowed types. Remove redundant constraints on
<code>Real</code>.</p></li>
<li><p>In <strong>[linalg.algs.reqs]</strong>, clarify that “unique
layout” for output matrix, vector, or object types means
<code>is_always_unique()</code> equals <code>true</code>.</p></li>
<li><p>Change file format from Markdown to Bikeshed.</p></li>
<li><p>Impose requirements on the types on which algorithms compute, and
on the algorithms themselves (e.g., what rearrangements are permitted).
Add a section explaining how we came up with the requirements. Lift the
requirements into a new higher-level section that applies to the entire
contents of <strong>[linalg]</strong>, not just to
<strong>[linalg.algs]</strong>.</p></li>
<li><p>Add “Overview of contents” section.</p></li>
<li><p>In the last review, LEWG had asked us to consider using
exposition-only concepts and <code>requires</code> clauses to express
requirements more clearly. We decided not to do so, because we did not
think it would add clarity.</p></li>
<li><p>Add more examples.</p></li>
</ul></li>
<li><p>Revision 5 (electronic), to be submitted 2021-10-15</p>
<ul>
<li>P0009R13 (to be submitted 2021-10-15) changes <code>mdspan</code> to
use <code>operator[]</code> instead of <code>operator()</code> as the
array access operator. Revision 5 of P1673 adopts this change, and is
“rebased” atop P1673R5.</li>
</ul></li>
<li><p>Revision 6 (electronic), to be submitted 2021-12-15</p>
<ul>
<li><p>Update references to P0009 (P0009R14) and P2128
(P2128R6).</p></li>
<li><p>Fix typos in <code>*rank_2k</code> descriptions.</p></li>
<li><p>Remove references to any <code>mdspan</code> rank greater than 2.
(These were left over from earlier versions of the proposal that
included “batched” operations.)</p></li>
<li><p>Fix <code>vector_sum_of_squares</code> name in BLAS comparison
table.</p></li>
<li><p>Replace “Requires” with “Preconditions,” per new wording
guidelines.</p></li>
<li><p>Remove all overloads of
<code>symmetric_matrix_rank_k_update</code> and
<code>hermitian_matrix_rank_k_update</code> that do not take an
<code>alpha</code> parameter. This prevents ambiguity between overloads
that take <code>ExecutionPolicy&amp;&amp;</code> but not
<code>alpha</code>, and overloads that take <code>alpha</code> but not
<code>ExecutionPolicy&amp;&amp;</code>.</p></li>
<li><p>Harmonize with the implementation, by adding
<code>operator+</code>, <code>operator*</code>, and comparison operators
to <code>conjugated_scalar</code>.</p></li>
</ul></li>
<li><p>Revision 7 (electronic), to be submitted 2022-04-15</p>
<ul>
<li><p>Update author affiliations and e-mail addresses</p></li>
<li><p>Update proposal references</p></li>
<li><p>Fix typo observed
<a href="https://github.com/kokkos/stdBLAS/issues/158">here</a></p></li>
<li><p>Add missing <code>ExecutionPolicy</code> overload of in-place
<code>triangular_matrix_vector_product</code>; issue was observed
<a href="https://github.com/kokkos/stdBLAS/issues/150">here</a></p></li>
<li><p>Fix mixed-up order of <code>sum_of_squares_result</code>
aggregate initialization arguments in <code>vector_norm2</code>
note</p></li>
<li><p>Fill in missing parts of <code>matrix_frob_norm</code> and
<code>vector_norm2</code> specification, addressing
<a href="https://github.com/kokkos/stdBLAS/issues/143">this
issue</a></p></li>
</ul></li>
<li><p>Revision 8 (electronic), to be submitted 2022-05-15</p>
<ul>
<li><p>Fix <code>Triangle</code> and <code>R[0,0]</code> in Cholesky
TSQR example</p></li>
<li><p>Explain why we apply <code>Triangle</code> to the possibly
transformed input matrix, while the BLAS applies <code>UPLO</code> to
the original input matrix</p></li>
<li><p>Optimize <code>transposed</code> for all known layouts, so as to
avoid use of <code>layout_transpose</code> when not needed; fix
computation of strides for transposed layouts</p></li>
<li><p>Fix matrix extents in constraints and mandates for
<code>symmetric_matrix_rank_k_update</code> and
<code>hermitian_matrix_rank_k_update</code> (thanks to Mikołaj Zuzek
(NexGen Analytics, <code>mikolaj.zuzek@ng-analytics.com</code>) for
reporting the issue)</p></li>
<li><p>Resolve vagueness in <code>const</code>ness of return type of
<code>transposed</code></p></li>
<li><p>Resolve vagueness in <code>const</code>ness of return type of
<code>scaled</code>, and make its element type the type of the product,
rather than forcing it back to the input <code>mdspan</code>’s element
type</p></li>
<li><p>Remove <code>decay</code> member function from
<code>accessor_conjugate</code> and <code>accessor_scaled</code>, as it
is no longer part of <code>mdspan</code>’s accessor policy
requirements</p></li>
<li><p>Make sure <code>accessor_conjugate</code> and
<code>conjugated</code> work correctly for user-defined complex types,
introduce <em><code>conj-if-needed</code></em> to simplify wording, and
resolve vagueness in <code>const</code>ness of return type of
<code>conjugated</code>. Make sure that
<em><code>conj-if-needed</code></em> works for custom types where
<code>conj</code> is not type-preserving. (Thanks to Yu You (NVIDIA,
yuyou@nvidia.com) and Phil Miller (Intense Computing,
<code>phil.miller@intensecomputing.com</code>) for helpful
discussions.)</p></li>
<li><p>Fix typo in <code>givens_rotation_setup</code> for complex
numbers, and other typos (thanks to Phil Miller for reporting the
issue)</p></li>
</ul></li>
<li><p>Revision 9 (electronic), to be submitted 2022-06-15</p>
<ul>
<li><p>Apply to-be-submitted P0009R17 changes (see P2553 in particular)
to all layouts, accessors, and examples in this proposal.</p></li>
<li><p>Improve
<code>triangular_matrix_matrix_{left,right}_solve()</code> “mathematical
expression of the algorithm” wording.</p></li>
<li><p><code>layout_blas_packed</code>: Fix
<code>required_span_size()</code> and <code>operator()</code>
wording</p></li>
<li><p>Make sure all definitions of lower and upper triangle are
consistent.</p></li>
<li><p>Changes to <code>layout_transpose</code>:</p>
<ul>
<li><p>Make
<code>layout_transpose::mapping(const nested_mapping_type&amp;)</code>
constructor <code>explicit</code>, to avoid inadvertent
transposition.</p></li>
<li><p>Remove the following Constraint on
<code>layout_transpose::mapping</code>: “for all specializations
<code>E</code> of <code>extents</code> with <code>E::rank()</code> equal
to 2,
<code>typename Layout::template mapping&lt;E&gt;::is_always_unique()</code>
is <code>true</code>.” (This Constraint was not correct, because the
underlying mapping is allowed to be nonunique.)</p></li>
<li><p>Make <code>layout_transpose::mapping::stride</code> wording
independent of <code>rank()</code> equals 2 constraint, to improve
consistency with rest of <code>layout_transpose</code> wording.</p></li>
</ul></li>
<li><p>Changes to <code>scaled</code> and <code>conjugated</code>:</p>
<ul>
<li><p>Include and specify all the needed overloaded arithmetic
operators for <code>scaled_scalar</code> and
<code>conjugated_scalar</code>, and fix <code>accessor_scaled</code> and
<code>accessor_conjugate</code> accordingly.</p></li>
<li><p>Simplify <code>scaled</code> to ensure preservation of order of
operations.</p></li>
<li><p>Add missing <code>nested_accessor()</code> to
<code>accessor_scaled</code>.</p></li>
<li><p>Add hidden friends <code>abs</code>, <code>real</code>,
<code>imag</code>, and <code>conj</code> to common subclass of
<code>scaled_scalar</code> and <code>conjugated_scalar</code>. Add
wording to algorithms that use <code>abs</code>, <code>real</code>,
and/or <code>imag</code>, to indicate that these functions are to be
found by unqualified lookup. (Algorithms that use conjugation already
use <em><code>conj-if-needed</code></em> in their wording.)</p></li>
</ul></li>
<li><p>Changes suggested by SG6 small group review on 2022/06/09</p>
<ul>
<li><p>Make existing exposition-only function
<em><code>conj-if-needed</code></em> use <code>conj</code> if it can
find it via unqualified (ADL-only) lookup, otherwise be the identity.
Make it a function object instead of a function, to prevent ADL
issues.</p></li>
<li><p>Algorithms that mathematically need to do division can now
distinguish left division and right division (for the case of
noncommutative multiplication), by taking an optional
<code>BinaryDivideOp</code> binary function object parameter. If none is
given, binary <code>operator/</code> is used.</p></li>
</ul></li>
<li><p>Changes suggested by LEWG review of P1673R8 on 2022/05/24</p>
<ul>
<li><p>LEWG asked us to add a section to the paper explaining why we
don’t define an interface for customization of the “back-end” optimized
BLAS operations. This section already existed, but we rewrote it to
improve clarity. Please see the section titled “We do not require using
the BLAS library or any particular ‘back-end’.”</p></li>
<li><p>LEWG asked us to add a section to the paper showing how BLAS 1
and ranges algorithms would coexist. We added this section, titled
“Criteria for including BLAS 1 algorithms; coexistence with
ranges.”</p></li>
<li><p>Address LEWG feedback to defer support for custom complex number
types (but see above SG6 small group response).</p></li>
</ul></li>
<li><p>Fix P1674 links to point to R2.</p></li>
</ul></li>
<li><p>Revision 10 (electronic), submitted 2022-10-15</p>
<ul>
<li><p>Revise <code>scaled</code> and <code>conjugated</code>
wording.</p></li>
<li><p>Make all matrix view functions <code>constexpr</code>.</p></li>
<li><p>Rebase atop P2642R1. Remove wording saying that we rebase atop
P0009R17. (We don’t need that any more, because P0009 was merged into
the current C++ draft.)</p></li>
<li><p>Remove <code>layout_blas_general</code>, as it has been replaced
with the layouts proposed by P2642 (<code>layout_left_padded</code> and
<code>layout_right_padded</code>).</p></li>
<li><p>Update <code>layout_blas_packed</code> to match mdspan’s other
layout mappings in the current C++ Standard draft.</p></li>
<li><p>Update accessors to match mdspan’s other accessors in the current
C++ Standard draft.</p></li>
<li><p>Update non-wording to reflect current status of
<code>mdspan</code> (voted into C++ Standard draft) and
<code>submdspan</code> (P2630).</p></li>
</ul></li>
<li><p>Revision 11, to be submitted 2023-01-15</p>
<ul>
<li><p>Remove requirement that <code>in_{vector,matrix,object}*_t</code>
have unique layout.</p></li>
<li><p>Change from name-based requirements
(<code>in_{vector,matrix,object}*_t</code>) to exposition-only concepts.
(This is our interpretation of LEWG’s Kona 2022/11/10 request to
“explore expressing constraints with concepts instead of named type
requirements” (see
https://github.com/cplusplus/papers/issues/557#issuecomment-1311054803).)
Add new section for exposition-only concepts and traits.</p></li>
<li><p>Add new exposition-only concept
<em><code>possibly-packed-inout-matrix</code></em> to constrain
symmetric and Hermitian update algorithms. These may write either to a
unique-layout mdspan or to a <code>layout_blas_packed</code> mdspan
(whose layout is nonunique).</p></li>
<li><p>Remove Constraints made redundant by the new exposition-only
concepts.</p></li>
<li><p>Remove unnecessary constraint on all algorithms that input
<code>mdspan</code> parameter(s) have unique layout.</p></li>
<li><p>Remove the requirement that vector / matrix / object template
parameters may deduce a <code>const</code> lvalue reference or a
(non-<code>const</code>) rvalue reference to an <code>mdspan</code>. The
new exposition-only concepts make this unnecessary.</p></li>
<li><p>Fix <code>dot</code> Remarks to include both vector
types.</p></li>
<li><p>Fix wording of several functions and examples to use
<code>mdspan</code>’s <code>value_type</code> alias instead of its
(potentially cv-qualified) <code>element_type</code> alias. This
includes <code>dot</code>, <code>vector_sum_of_squares</code>,
<code>vector_norm2</code>, <code>vector_abs_sum</code>,
<code>matrix_frob_norm</code>, <code>matrix_one_norm</code>,
<code>matrix_inf_norm</code>, and the QR factorization example.</p></li>
<li><p>Make <code>matrix_vector_product</code> template parameter order
consistent with parameter order.</p></li>
<li><p>Follow LEWG guidance to simplify Effects and Constraints (e.g.,
removing wording referring to the “the mathematical expression for the
algorithm”) (as a kind of expression-implying constraints) by describing
them mathematically (in math font). This is our interpretation of the
“hand wavy do math” poll option that received a majority of votes at
Kona on 2022/11/10 (see
https://github.com/cplusplus/papers/issues/557#issuecomment-1311054803).
Revise <strong>[linalg.reqs.val]</strong> accordingly.</p></li>
<li><p>Change <code>matrix_one_norm</code> Precondition (that the result
of <code>abs</code> of a matrix element is convertible to
<code>T</code>) to a Constraint.</p></li>
<li><p>Change <code>vector_abs_sum</code> Precondition (that the result
of <code>init + abs(v[i])</code> is convertible to <code>T</code>) to a
Constraint.</p></li>
<li><p>Reformat entire document to use Pandoc instead of Bikeshed. This
made it possible to add paragraph numbers and fix exposition-only
italics.</p></li>
<li><p>In <em><code>conjugated-scalar</code></em>, make
<em><code>conjugatable</code></em><code>&lt;ReferenceValue&gt;</code> a
Constraint instead of a Mandate.</p></li>
<li><p>Delete “If an algorithm in <em>[linalg.algs]</em> accesses the
elements of an <em><code>out-vector</code></em>,
<em><code>out-matrix</code></em>, or <em><code>out-object</code></em>,
it will do so in write-only fashion.” This would prevent implementations
from, e.g., zero-initializing the elements and then updating them with
<code>+=</code>.</p></li>
<li><p>Rebase atop P2642R2 (updating from R1).</p></li>
<li><p>Add <code>explicit</code> defaulted default constructors to all
the tag types, in imitation of <code>in_place_t</code>.</p></li>
<li><p>If two objects refer to the same matrix or vector, we no longer
say that they must have the same layout. First, “same layout” doesn’t
have to mean the same type. For example, a
<code>layout_stride::mapping</code> instance may represent the same
layout as a <code>layout_left::mapping</code> instance. Second, the two
objects can’t represent “the same matrix” or “the same vector” if they
have different layout mappings (in the mathematical sense, not in the
type sense).</p></li>
<li><p>Make sure that all updating methods say that the input(s) can be
the same as the output (not all inputs, just the ones for which that
makes sense – e.g., for the matrix-vector product <span class="math inline"><em>z</em> = <em>y</em> + <em>A</em><em>x</em></span>,
<code>y</code> and <code>z</code> can refer to the same vector, but not
<code>x</code> and <code>z</code>).</p></li>
<li><p>Change <code>givens_rotation_setup</code> to return outputs in
the new <code>givens_rotation_setup_result</code> struct, instead of as
output parameters.</p></li>
</ul></li>
</ul>
<h1 data-number="3" id="purpose-of-this-paper"><span class="header-section-number">3</span> Purpose of this paper<a href="#purpose-of-this-paper" class="self-link"></a></h1>
<p>This paper proposes a C++ Standard Library dense linear algebra
interface based on the dense Basic Linear Algebra Subroutines (BLAS).
This corresponds to a subset of the <a href="http://www.netlib.org/blas/blast-forum/blas-report.pdf">BLAS
Standard</a>. Our proposal implements the following classes of
algorithms on arrays that represent matrices and vectors:</p>
<ul>
<li><p>elementwise vector sums;</p></li>
<li><p>multiplying all elements of a vector or matrix by a
scalar;</p></li>
<li><p>2-norms and 1-norms of vectors;</p></li>
<li><p>vector-vector, matrix-vector, and matrix-matrix products
(contractions);</p></li>
<li><p>low-rank updates of a matrix;</p></li>
<li><p>triangular solves with one or more “right-hand side” vectors;
and</p></li>
<li><p>generating and applying plane (Givens) rotations.</p></li>
</ul>
<p>Our algorithms work with most of the matrix storage formats that the
BLAS Standard supports:</p>
<ul>
<li><p>“general” dense matrices, in column-major or row-major
format;</p></li>
<li><p>symmetric or Hermitian (for complex numbers only) dense matrices,
stored either as general dense matrices, or in a packed format;
and</p></li>
<li><p>dense triangular matrices, stored either as general dense
matrices or in a packed format.</p></li>
</ul>
<p>Our proposal also has the following distinctive characteristics.</p>
<ul>
<li><p>It uses free functions, not arithmetic operator
overloading.</p></li>
<li><p>The interface is designed in the spirit of the C++ Standard
Library’s algorithms.</p></li>
<li><p>It uses <code>mdspan</code> (P0009 and follow-on papers, which
have been adopted into the C++23 draft), a multidimensional array view,
to represent matrices and vectors.</p></li>
<li><p>The interface permits optimizations for matrices and vectors with
small compile-time dimensions; the standard BLAS interface does
not.</p></li>
<li><p>Each of our proposed operations supports all element types for
which that operation makes sense, unlike the BLAS, which only supports
four element types.</p></li>
<li><p>Our operations permit “mixed-precision” computation with matrices
and vectors that have different element types. This subsumes most
functionality of the Mixed-Precision BLAS specification, comprising
Chapter 4 of the
<a href="http://www.netlib.org/blas/blast-forum/blas-report.pdf">BLAS
Standard</a>.</p></li>
<li><p>Like the C++ Standard Library’s algorithms, our operations take
an optional execution policy argument. This is a hook to support
parallel execution and hierarchical parallelism (through the proposed
executor extensions to execution policies; see P1019R2).</p></li>
<li><p>Unlike the BLAS, our proposal can be expanded to support
“batched” operations (see P1417R0) with almost no interface differences.
This will support machine learning and other applications that need to
do many small matrix or vector operations at once.</p></li>
</ul>
<p>Here are some examples of what this proposal offers. In these
examples, we ignore <code>std::</code> namespace qualification for
anything in our proposal or for <code>mdspan</code>. We start with a
“hello world” that scales the elements of a 1-D <code>mdspan</code> by a
constant factor, first sequentially, then in parallel.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">size_t</span> N <span class="op">=</span> <span class="dv">40</span>;</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">double</span><span class="op">&gt;</span> x_vec<span class="op">(</span>N<span class="op">)</span>;</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  mdspan x<span class="op">(</span>x_vec<span class="op">.</span>data<span class="op">()</span>, N<span class="op">)</span>;</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> N; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    x<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> <span class="dt">double</span><span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  linalg<span class="op">::</span>scale<span class="op">(</span><span class="fl">2.0</span>, x<span class="op">)</span>; <span class="co">// x = 2.0 * x</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  linalg<span class="op">::</span>scale<span class="op">(</span>std<span class="op">::</span>execution<span class="op">::</span>par_unseq, <span class="fl">3.0</span>, x<span class="op">)</span>;</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> N; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span>x<span class="op">[</span>i<span class="op">]</span> <span class="op">==</span> <span class="fl">6.0</span> <span class="op">*</span> <span class="dt">double</span><span class="op">(</span>i<span class="op">))</span>;</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p>Here is a matrix-vector product example. It illustrates the
<code>scaled</code> function that makes our interface more concise,
while still permitting the BLAS’ performance optimization of fusing
computations with multiplications by a scalar. It also shows the ability
to exploit dimensions known at compile time, and to mix compile-time and
run-time dimensions arbitrarily.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">size_t</span> N <span class="op">=</span> <span class="dv">40</span>;</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">size_t</span> M <span class="op">=</span> <span class="dv">20</span>;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">double</span><span class="op">&gt;</span> A_vec<span class="op">(</span>N<span class="op">*</span>M<span class="op">)</span>;</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">double</span><span class="op">&gt;</span> x_vec<span class="op">(</span>M<span class="op">)</span>;</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>array<span class="op">&lt;</span><span class="dt">double</span>, N<span class="op">&gt;</span> y_vec<span class="op">(</span>N<span class="op">)</span>;</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>mdspan A<span class="op">(</span>A_vec<span class="op">.</span>data<span class="op">()</span>, N, M<span class="op">)</span>;</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>mdspan x<span class="op">(</span>x_vec<span class="op">.</span>data<span class="op">()</span>, M<span class="op">)</span>;</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>mdspan y<span class="op">(</span>y_vec<span class="op">.</span>data<span class="op">()</span>, N<span class="op">)</span>;</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span><span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> A<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> j <span class="op">=</span> <span class="dv">0</span>; j <span class="op">&lt;</span> A<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>; <span class="op">++</span>j<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>    A<span class="op">[</span>i,j<span class="op">]</span> <span class="op">=</span> <span class="fl">100.0</span> <span class="op">*</span> i <span class="op">+</span> j;</span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span><span class="op">(</span><span class="dt">int</span> j <span class="op">=</span> <span class="dv">0</span>; j <span class="op">&lt;</span> x<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>j<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>  x<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> <span class="fl">1.0</span> <span class="op">*</span> j;</span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span><span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> y<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>  y<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> <span class="op">-</span><span class="fl">1.0</span> <span class="op">*</span> i;</span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a>linalg<span class="op">::</span>matrix_vector_product<span class="op">(</span>A, x, y<span class="op">)</span>; <span class="co">// y = A * x</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a><span class="co">// y = 0.5 * y + 2 * A * x</span></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a>linalg<span class="op">::</span>matrix_vector_product<span class="op">(</span>std<span class="op">::</span>execution<span class="op">::</span>par,</span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a>  linalg<span class="op">::</span>scaled<span class="op">(</span><span class="fl">2.0</span>, A<span class="op">)</span>, x,</span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a>  linalg<span class="op">::</span>scaled<span class="op">(</span><span class="fl">0.5</span>, y<span class="op">)</span>, y<span class="op">)</span>;</span></code></pre></div>
<p>This example illustrates the ability to perform mixed-precision
computations, and the ability to compute on subviews of a matrix or
vector by using <code>submdspan</code> (P2630). (<code>submdspan</code>
was separated from the rest of P0009 as a way to avoid delaying the
hopeful adoption of P0009 for C++23. The reference implementation of
<code>mdspan</code> includes <code>submdspan</code>.)</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">size_t</span> M <span class="op">=</span> <span class="dv">40</span>;</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;</span> A_vec<span class="op">(</span>M<span class="op">*</span><span class="dv">8</span><span class="op">*</span><span class="dv">4</span><span class="op">)</span>;</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">double</span><span class="op">&gt;</span> x_vec<span class="op">(</span>M<span class="op">*</span><span class="dv">4</span><span class="op">)</span>;</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">double</span><span class="op">&gt;</span> y_vec<span class="op">(</span>M<span class="op">*</span><span class="dv">8</span><span class="op">)</span>;</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>mdspan<span class="op">&lt;</span><span class="dt">float</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, dynamic_extent, <span class="dv">8</span>, <span class="dv">4</span><span class="op">&gt;&gt;</span> A<span class="op">(</span>A_vec<span class="op">.</span>data<span class="op">()</span>, M<span class="op">)</span>;</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">4</span>, dynamic_extent<span class="op">&gt;&gt;</span> x<span class="op">(</span>x_vec<span class="op">.</span>data<span class="op">()</span>, M<span class="op">)</span>;</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, dynamic_extent, <span class="dv">8</span><span class="op">&gt;&gt;</span> y<span class="op">(</span>y_vec<span class="op">.</span>data<span class="op">()</span>, M<span class="op">)</span>;</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> m <span class="op">=</span> <span class="dv">0</span>; m <span class="op">&lt;</span> A<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>m<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> A<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> j <span class="op">=</span> <span class="dv">0</span>; j <span class="op">&lt;</span> A<span class="op">.</span>extent<span class="op">(</span><span class="dv">2</span><span class="op">)</span>; <span class="op">++</span>j<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>      A<span class="op">[</span>m,i,j<span class="op">]</span> <span class="op">=</span> <span class="fl">1000.0</span> <span class="op">*</span> m <span class="op">+</span> <span class="fl">100.0</span> <span class="op">*</span> i <span class="op">+</span> j;</span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> x<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> m <span class="op">=</span> <span class="dv">0</span>; m <span class="op">&lt;</span> x<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>; <span class="op">++</span>m<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a>    x<span class="op">[</span>i,m<span class="op">]</span> <span class="op">=</span> <span class="fl">33.</span> <span class="op">*</span> i <span class="op">+</span> <span class="fl">0.33</span> <span class="op">*</span> m;</span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> m <span class="op">=</span> <span class="dv">0</span>; m <span class="op">&lt;</span> y<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>m<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> y<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a>    y<span class="op">[</span>m,i<span class="op">]</span> <span class="op">=</span> <span class="fl">33.</span> <span class="op">*</span> m <span class="op">+</span> <span class="fl">0.33</span> <span class="op">*</span> i;</span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> m <span class="op">=</span> <span class="dv">0</span>; m <span class="op">&lt;</span> M; <span class="op">++</span>m<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> A_m <span class="op">=</span> submdspan<span class="op">(</span>A, m, full_extent, full_extent<span class="op">)</span>;</span>
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> x_m <span class="op">=</span> submdspan<span class="op">(</span>x, full_extent, m<span class="op">)</span>;</span>
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> y_m <span class="op">=</span> submdspan<span class="op">(</span>y, m, full_extent<span class="op">)</span>;</span>
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true" tabindex="-1"></a>  <span class="co">// y_m = A * x_m</span></span>
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true" tabindex="-1"></a>  linalg<span class="op">::</span>matrix_vector_product<span class="op">(</span>A_m, x_m, y_m<span class="op">)</span>;</span>
<span id="cb3-35"><a href="#cb3-35" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h1 data-number="4" id="overview-of-contents"><span class="header-section-number">4</span> Overview of contents<a href="#overview-of-contents" class="self-link"></a></h1>
<p>Section
<a href="#interoperable-with-other-linear-algebra-proposals"><span class="secno">5</span></a> explains how this proposal is interoperable
with other linear algebra proposals currently under WG21 review. In
particular, we believe this proposal is complementary to P1385R6, and
the authors of P1385R6 have expressed the same view.</p>
<p>Section
<a href="#why-include-dense-linear-algebra-in-the-c-standard-library"><span class="secno">6</span></a> motivates considering <em>any</em> dense
linear algebra proposal for the C++ Standard Library.</p>
<p>Section
<a href="#why-base-a-c-linear-algebra-library-on-the-blas"><span class="secno">7</span></a> shows why we chose the BLAS as a starting
point for our proposed library. The BLAS is an existing standard with
decades of use, a rich set of functions, and many optimized
implementations.</p>
<p>Section <a href="#criteria-for-including-algorithms"><span class="secno">8</span></a> lists what we consider general criteria for
including algorithms in the C++ Standard Library. We rely on these
criteria to justify the algorithms in this proposal.</p>
<p>Section <a href="#notation-and-conventions"><span class="secno">9</span></a> describes BLAS notation and conventions in
C++ terms. Understanding this will give readers context for algorithms,
and show how our proposed algorithms expand on BLAS functionality.</p>
<p>Section <a href="#what-we-exclude-from-the-design"><span class="secno">10</span></a> lists functionality that we intentionally
exclude from our proposal. We imitate the BLAS in aiming to be a set of
“performance primitives” on which external libraries or applications may
build a more complete linear algebra solution.</p>
<p>Section <a href="#design-justification"><span class="secno">11</span></a> elaborates on our design justification. This
section explains</p>
<ul>
<li><p>why we use <code>mdspan</code> to represent matrix and vector
parameters;</p></li>
<li><p>how we translate the BLAS’ Fortran-centric idioms into
C++;</p></li>
<li><p>how the BLAS’ different “matrix types” map to different
algorithms, rather than different <code>mdspan</code> layouts;</p></li>
<li><p>how we express quality-of-implementation recommendations about
avoiding undue overflow and underflow; and</p></li>
<li><p>how we impose requirements on algorithms’ behavior and on the
various value types that algorithms encounter.</p></li>
</ul>
<p>Section <a href="#future-work"><span class="secno">12</span></a>
lists future work, that is, ways future proposals could build on this
one.</p>
<p>Section
<a href="#data-structures-and-utilities-borrowed-from-other-proposals"><span class="secno">13</span></a> gives the data structures and utilities from
other proposals on which we depend. In particular, we rely heavily on
<code>mdspan</code> (P0009), and add custom layouts and accessors.</p>
<p>Section <a href="#acknowledgments"><span class="secno">14</span></a>
credits funding agencies and contributors.</p>
<p>Section <a href="#references"><span class="secno">15</span></a> is
our bibliography.</p>
<p>Section <a href="#wording"><span class="secno">16</span></a> is where
readers will find the normative wording we propose.</p>
<p>Finally, Section <a href="#examples"><span class="secno">17</span></a> gives some more elaborate examples of linear
algebra algorithms that use our proposal. The examples show how
<code>mdspan</code>’s features let users easily describe “submatrices”
with <code>submdspan</code>, proposed in P2630 as a follow-on to mdspan.
(The reference implementation of <code>mdspan</code> includes
<code>submdspan</code>.) This integrates naturally with “block”
factorizations of matrices. The resulting notation is concise, yet still
computes in place, without unnecessary copies of any part of the
matrix.</p>
<p>Here is a table that maps between Reference BLAS function name, and
algorithm or function name in our proposal. The mapping is not always
one to one. “N/A” in the “BLAS name(s)” field means that the function is
not in the BLAS.</p>
<table>
<tr>
<th>
BLAS name(s)
</th>
<th>
Our name(s)
</th>
</tr>
<tr>
<td>
xLARTG
</td>
<td>
<code>givens_rotation_setup</code>
</td>
</tr>
<tr>
<td>
xROT
</td>
<td>
<code>givens_rotation_apply</code>
</td>
</tr>
<tr>
<td>
xSWAP
</td>
<td>
<code>swap_elements</code>
</td>
</tr>
<tr>
<td>
xSCAL
</td>
<td>
<code>scale</code>, <code>scaled</code>
</td>
</tr>
<tr>
<td>
xCOPY
</td>
<td>
<code>copy</code>
</td>
</tr>
<tr>
<td>
xAXPY
</td>
<td>
<code>add</code>, <code>scaled</code>
</td>
</tr>
<tr>
<td>
xDOT, xDOTU
</td>
<td>
<code>dot</code>
</td>
</tr>
<tr>
<td>
xDOTC
</td>
<td>
<code>dotc</code>
</td>
</tr>
<tr>
<td>
N/A
</td>
<td>
<code>vector_sum_of_squares</code>
</td>
</tr>
<tr>
<td>
xNRM2
</td>
<td>
<code>vector_norm2</code>
</td>
</tr>
<tr>
<td>
xASUM
</td>
<td>
<code>vector_abs_sum</code>
</td>
</tr>
<tr>
<td>
xIAMAX
</td>
<td>
<code>idx_abs_max</code>
</td>
</tr>
<tr>
<td>
N/A
</td>
<td>
<code>matrix_frob_norm</code>
</td>
</tr>
<tr>
<td>
N/A
</td>
<td>
<code>matrix_one_norm</code>
</td>
</tr>
<tr>
<td>
N/A
</td>
<td>
<code>matrix_inf_norm</code>
</td>
</tr>
<tr>
<td>
xGEMV
</td>
<td>
<code>matrix_vector_product</code>
</td>
</tr>
<tr>
<td>
xSYMV
</td>
<td>
<code>symmetric_matrix_vector_product</code>
</td>
</tr>
<tr>
<td>
xHEMV
</td>
<td>
<code>hermitian_matrix_vector_product</code>
</td>
</tr>
<tr>
<td>
xTRMV
</td>
<td>
<code>triangular_matrix_vector_product</code>
</td>
</tr>
<tr>
<td>
xTRSV
</td>
<td>
<code>triangular_matrix_vector_solve</code>
</td>
</tr>
<tr>
<td>
xGER, xGERU
</td>
<td>
<code>matrix_rank_1_update</code>
</td>
</tr>
<tr>
<td>
xGERC
</td>
<td>
<code>matrix_rank_1_update_c</code>
</td>
</tr>
<tr>
<td>
xSYR
</td>
<td>
<code>symmetric_matrix_rank_1_update</code>
</td>
</tr>
<tr>
<td>
xHER
</td>
<td>
<code>hermitian_matrix_rank_1_update</code>
</td>
</tr>
<tr>
<td>
xSYR2
</td>
<td>
<code>symmetric_matrix_rank_2_update</code>
</td>
</tr>
<tr>
<td>
xHER2
</td>
<td>
<code>hermitian_matrix_rank_2_update</code>
</td>
</tr>
<tr>
<td>
xGEMM
</td>
<td>
<code>matrix_product</code>
</td>
</tr>
<tr>
<td>
xSYMM
</td>
<td>
<code>symmetric_matrix_{left,right}_product</code>
</td>
</tr>
<tr>
<td>
xHEMM
</td>
<td>
<code>hermitian_matrix_{left,right}_product</code>
</td>
</tr>
<tr>
<td>
xTRMM
</td>
<td>
<code>triangular_matrix_{left,right}_product</code>
</td>
</tr>
<tr>
<td>
xSYRK
</td>
<td>
<code>symmetric_matrix_rank_k_update</code>
</td>
</tr>
<tr>
<td>
xHERK
</td>
<td>
<code>hermitian_matrix_rank_k_update</code>
</td>
</tr>
<tr>
<td>
xSYR2K
</td>
<td>
<code>symmetric_matrix_rank_2k_update</code>
</td>
</tr>
<tr>
<td>
xHER2K
</td>
<td>
<code>hermitian_matrix_rank_2k_update</code>
</td>
</tr>
<tr>
<td>
xTRSM
</td>
<td>
<code>triangular_matrix_matrix_{left,right}_solve</code>
</td>
</tr>
</table>
<h1 data-number="5" id="interoperable-with-other-linear-algebra-proposals"><span class="header-section-number">5</span> Interoperable with other linear
algebra proposals<a href="#interoperable-with-other-linear-algebra-proposals" class="self-link"></a></h1>
<p>We believe this proposal is complementary to P1385R6, a proposal for
a C++ Standard linear algebra library that introduces matrix and vector
classes with overloaded arithmetic operators. The P1385 authors and we
have expressed together in a joint paper,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1891r0.pdf">P1891</a>,
that P1673 and P1385 “are orthogonal. They are not competing papers; …
there is no overlap of functionality.”</p>
<p>Many of us have had experience using and implementing matrix and
vector operator arithmetic libraries like what P1385 proposes. We
designed P1673 in part as a natural foundation or implementation layer
for such libraries. Our view is that a free function interface like
P1673’s clearly separates algorithms from data structures, and more
naturally allows for a richer set of operations such as what the BLAS
provides. Our paper <a href="https://wg21.link/p1674">P1674</a> explains
why we think our proposal is a minimal C++ “respelling” of the BLAS.</p>
<p>A natural extension of the present proposal would include accepting
P1385’s matrix and vector objects as input for the algorithms proposed
here. A straightforward way to do that would be for P1385’s matrix and
vector objects to make views of their data available as
<code>mdspan</code>.</p>
<h1 data-number="6" id="why-include-dense-linear-algebra-in-the-c-standard-library"><span class="header-section-number">6</span> Why include dense linear algebra
in the C++ Standard Library?<a href="#why-include-dense-linear-algebra-in-the-c-standard-library" class="self-link"></a></h1>
<ol type="1">
<li><p>“Direction for ISO C++” (P0939R4) explicitly calls out “Linear
Algebra” as a potential priority for C++23.</p></li>
<li><p>C++ applications in “important application areas” (see P0939R4)
have depended on linear algebra for a long time.</p></li>
<li><p>Linear algebra is like <code>sort</code>: obvious algorithms are
slow, and the fastest implementations call for hardware-specific
tuning.</p></li>
<li><p>Dense linear algebra is core functionality for most of linear
algebra, and can also serve as a building block for tensor
operations.</p></li>
<li><p>The C++ Standard Library includes plenty of “mathematical
functions.” Linear algebra operations like matrix-matrix multiply are at
least as broadly useful.</p></li>
<li><p>The set of linear algebra operations in this proposal are derived
from a well-established, standard set of algorithms that has changed
very little in decades. It is one of the strongest possible examples of
standardizing existing practice that anyone could bring to C++.</p></li>
<li><p>This proposal follows in the footsteps of many recent successful
incorporations of existing standards into C++, including the UTC and TAI
standard definitions from the International Telecommunications Union,
the time zone database standard from the International Assigned Numbers
Authority, and the ongoing effort to integrate the ISO unicode
standard.</p></li>
</ol>
<p>Linear algebra has had wide use in C++ applications for nearly three
decades (see P1417R0 for a historical survey). For much of that time,
many third-party C++ libraries for linear algebra have been available.
Many different subject areas depend on linear algebra, including machine
learning, data mining, web search, statistics, computer graphics,
medical imaging, geolocation and mapping, engineering, and physics-based
simulations.</p>
<p>“Directions for ISO C++” (P0939R4) not only lists “Linear Algebra”
explicitly as a potential C++23 priority, it also offers the following
in support of adding linear algebra to the C++ Standard Library.</p>
<ul>
<li><p>P0939R4 calls out “Support for demanding applications” in
“important application areas, such as medical, finance, automotive, and
games (e.g., key libraries…)” as an “area of general concern” that “we
should not ignore.” All of these areas depend on linear
algebra.</p></li>
<li><p>“Is my proposal essential for some important application domain?”
Many large and small private companies, science and engineering
laboratories, and academics in many different fields all depend on
linear algebra.</p></li>
<li><p>“We need better support for modern hardware”: Modern hardware
spends many of its cycles in linear algebra. For decades, hardware
vendors, some represented at WG21 meetings, have provided and continue
to provide features specifically to accelerate linear algebra
operations. Some of them even implement specific linear algebra
operations directly in hardware. Examples include NVIDIA’s
<a href="https://www.nvidia.com/en-us/data-center/tensorcore/">Tensor
Cores</a> and Cerebras’
<a href="https://www.cerebras.net/product/#chip">Wafer Scale Engine</a>.
Several large computer system vendors offer optimized linear algebra
libraries based on or closely resembling the BLAS. These include AMD’s
BLIS, ARM’s Performance Libraries, Cray’s LibSci, Intel’s Math Kernel
Library (MKL), IBM’s Engineering and Scientific Subroutine Library
(ESSL), and NVIDIA’s cuBLAS.</p></li>
</ul>
<p>Obvious algorithms for some linear algebra operations like dense
matrix-matrix multiply are asymptotically slower than less-obvious
algorithms. (Please refer to a survey one of us coauthored,
<a href="https://doi.org/10.1017/S0962492914000038"> “Communication
lower bounds and optimal algorithms for numerical linear algebra.”</a>
Furthermore, writing the fastest dense matrix-matrix multiply depends on
details of a specific computer architecture. This makes such operations
comparable to <code>sort</code> in the C++ Standard Library: worth
standardizing, so that Standard Library implementers can get them right
and hardware vendors can optimize them. In fact, almost all C++ linear
algebra libraries end up calling non-C++ implementations of these
algorithms, especially the implementations in optimized BLAS libraries
(see below). In this respect, linear algebra is also analogous to
standard library features like <code>random_device</code>: often
implemented directly in assembly or even with special hardware, and thus
an essential component of allowing no room for another language “below”
C++ (see P0939R4) and Stroustrup’s “The Design and Evolution of
C++”).</p>
<p>Dense linear algebra is the core component of most algorithms and
applications that use linear algebra, and the component that is most
widely shared over different application areas. For example, tensor
computations end up spending most of their time in optimized dense
linear algebra functions. Sparse matrix computations get best
performance when they spend as much time as possible in dense linear
algebra.</p>
<p>The C++ Standard Library includes many
<a href="https://eel.is/c++draft/sf.cmath">“mathematical special
functions”</a> (<strong>[sf.cmath]</strong>), like incomplete elliptic
integrals, Bessel functions, and other polynomials and functions named
after various mathematicians. Any of them comes with its own theory and
set of applications for which robust and accurate implementations are
indispensible. We think that linear algebra operations are at least as
broadly useful, and in many cases significantly more so.</p>
<h1 data-number="7" id="why-base-a-c-linear-algebra-library-on-the-blas"><span class="header-section-number">7</span> Why base a C++ linear algebra
library on the BLAS?<a href="#why-base-a-c-linear-algebra-library-on-the-blas" class="self-link"></a></h1>
<ol type="1">
<li><p>The BLAS is a standard that codifies decades of existing
practice.</p></li>
<li><p>The BLAS separates “performance primitives” for hardware experts
to tune, from mathematical operations that rely on those primitives for
good performance.</p></li>
<li><p>Benchmarks reward hardware and system vendors for providing
optimized BLAS implementations.</p></li>
<li><p>Writing a fast BLAS implementation for common element types is
nontrivial, but well understood.</p></li>
<li><p>Optimized third-party BLAS implementations with liberal software
licenses exist.</p></li>
<li><p>Building a C++ interface on top of the BLAS is a straightforward
exercise, but has pitfalls for unaware developers.</p></li>
</ol>
<p>Linear algebra has had a cross-language standard, the Basic Linear
Algebra Subroutines (BLAS), since 2002. The Standard came out of a
<a href="http://www.netlib.org/blas/blast-forum/">standardization
process</a> that started in 1995 and held meetings three times a year
until 1999. Participants in the process came from industry, academia,
and government research laboratories. The dense linear algebra subset of
the BLAS codifies forty years of evolving practice, and has existed in
recognizable form since 1990 (see P1417R0).</p>
<p>The BLAS interface was specifically designed as the distillation of
the “computer science” or performance-oriented parts of linear algebra
algorithms. It cleanly separates operations most critical for
performance, from operations whose implementation takes expertise in
mathematics and rounding-error analysis. This gives vendors
opportunities to add value, without asking for expertise outside the
typical required skill set of a Standard Library implementer.</p>
<p>Well-established benchmarks such as the
<a href="https://www.top500.org/project/linpack/">LINPACK benchmark</a>,
reward computer hardware vendors for optimizing their BLAS
implementations. Thus, many vendors provide an optimized BLAS library
for their computer architectures. Writing fast BLAS-like operations is
not trivial, and depends on computer architecture. However, it is a
well-understood problem whose solutions could be parameterized for a
variety of computer architectures. See, for example,
<a href="https://doi.org/10.1145/1356052.1356053">Goto and van de Geijn
2008</a>. There are optimized third-party BLAS implementations for
common architectures, like
<a href="http://math-atlas.sourceforge.net/">ATLAS</a> and
<a href="https://www.tacc.utexas.edu/research-development/tacc-software/gotoblas2">GotoBLAS</a>.
A (slow but correct)
<a href="http://www.netlib.org/blas/#_reference_blas_version_3_8_0">reference
implementation of the BLAS</a> exists and it has a liberal software
license for easy reuse.</p>
<p>We have experience in the exercise of wrapping a C or Fortran BLAS
implementation for use in portable C++ libraries. We describe this
exercise in detail in our paper “Evolving a Standard C++ Linear Algebra
Library from the BLAS” <a href="https://wg21.link/p1674">(P1674)</a>. It
is straightforward for vendors, but has pitfalls for developers. For
example, Fortran’s application binary interface (ABI) differs across
platforms in ways that can cause run-time errors (even incorrect
results, not just crashing). Historical examples of vendors’ C BLAS
implementations have also had ABI issues that required work-arounds.
This dependence on ABI details makes availability in a standard C++
library valuable.</p>
<h1 data-number="8" id="criteria-for-including-algorithms"><span class="header-section-number">8</span> Criteria for including
algorithms<a href="#criteria-for-including-algorithms" class="self-link"></a></h1>
<h2 data-number="8.1" id="criteria-for-all-the-algorithms"><span class="header-section-number">8.1</span> Criteria for all the
algorithms<a href="#criteria-for-all-the-algorithms" class="self-link"></a></h2>
<p>We include algorithms in our proposal based on the following
criteria, ordered by decreasing importance. Many of our algorithms
satisfy multiple criteria.</p>
<ol type="1">
<li><p>Getting the desired asymptotic run time is nontrivial</p></li>
<li><p>Opportunity for vendors to provide hardware-specific
optimizations</p></li>
<li><p>Opportunity for vendors to provide quality-of-implementation
improvements, especially relating to accuracy or reproducibility with
respect to floating-point rounding error</p></li>
<li><p>User convenience (familiar name, or tedious to
implement)</p></li>
</ol>
<p>Regarding (1), “nontrivial” means “at least for novices to the
field.” Dense matrix-matrix multiply is a good example. Getting close to
the asymptotic lower bound on the number of memory reads and writes
matters a lot for performance, and calls for a nonintuitive loop
reordering. An analogy to the current C++ Standard Library is
<code>sort</code>, where intuitive algorithms that many humans use are
not asymptotically optimal.</p>
<p>Regarding (2), a good example is copying multidimensional arrays. The
<a href="https://github.com/kokkos/kokkos">Kokkos library</a> spends
about 2500 lines of code on multidimensional array copy, yet still
relies on system libraries for low-level optimizations. An analogy to
the current C++ Standard Library is <code>copy</code> or even
<code>memcpy</code>.</p>
<p>Regarding (3), accurate floating-point summation is nontrivial.
Well-meaning compiler optimizations might defeat even simple technqiues,
like compensated summation. The most obvious way to compute a vector’s
Euclidean norm (square root of sum of squares) can cause overflow or
underflow, even when the exact answer is much smaller than the overflow
threshold, or larger than the underflow threshold. Some users care
deeply about sums, even parallel sums, that always get the same answer,
despite rounding error. This can help debugging, for example. It is
possible to make floating-point sums completely independent of parallel
evaluation order. See e.g., the
<a href="https://bebop.cs.berkeley.edu/reproblas/">ReproBLAS</a> effort.
Naming these algorithms and providing <code>ExecutionPolicy</code>
customization hooks gives vendors a chance to provide these
improvements. An analogy to the current C++ Standard Library is
<code>hypot</code>, whose language in the C++ Standard alludes to the
tighter POSIX requirements.</p>
<p>Regarding (4), the C++ Standard Library is not entirely minimalist.
One example is <code>std::string::contains</code>. Existing Standard
Library algorithms already offered this functionality, but a member
<code>contains</code> function is easy for novices to find and use, and
avoids the tedium of comparing the result of <code>find</code> to
<code>npos</code>.</p>
<p>The BLAS exists mainly for the first two reasons. It includes
functions that were nontrivial for compilers to optimize in its time,
like scaled elementwise vector sums, as well as functions that generally
require human effort to optimize, like matrix-matrix multiply.</p>
<h2 data-number="8.2" id="criteria-for-including-blas-1-algorithms-coexistence-with-ranges"><span class="header-section-number">8.2</span> Criteria for including BLAS 1
algorithms; coexistence with ranges<a href="#criteria-for-including-blas-1-algorithms-coexistence-with-ranges" class="self-link"></a></h2>
<p>The BLAS developed in three “levels”: 1, 2, and 3. BLAS 1 includes
“vector-vector” operations like dot products, norms, and vector
addition. BLAS 2 includes “matrix-vector” operations like matrix-vector
products and outer products. BLAS 3 includes “matrix-matrix” operations
like matrix-matrix products and triangular solve with multiple
“right-hand side” vectors. The BLAS level coincides with the number of
nested loops in a naïve sequential implementation of the operation.
Increasing level also comes with increasing potential for data reuse.
For history of the BLAS “levels” and a bibliography, see
<a href="https://wg21.link/p1417">P1417</a>.</p>
<p>We mention this here because some reviewers have asked how the
algorithms in our proposal would coexist with the existing ranges
algorithms in the C++ Standard Library. This question actually encloses
two questions.</p>
<ol type="1">
<li><p>Will our proposed algorithms syntactically collide with existing
ranges algorithms?</p></li>
<li><p>How much overlap do our proposed algorithms have with the
existing ranges algorithms? (That is, do we really need these new
algorithms?)</p></li>
</ol>
<h3 data-number="8.2.1" id="low-risk-of-synactic-collision-with-ranges"><span class="header-section-number">8.2.1</span> Low risk of synactic
collision with ranges<a href="#low-risk-of-synactic-collision-with-ranges" class="self-link"></a></h3>
<p>We think there is low risk of our proposal colliding syntactically
with existing ranges algorithms, for the following reasons.</p>
<ul>
<li><p>We propose our algorithms in a new namespace
<code>std::linalg</code>.</p></li>
<li><p>None of the algorithms we propose share names with any existing
ranges algorithms.</p></li>
<li><p>We take care not to use <code>_view</code> as a suffix, in order
to avoid confusion or name collisions with “views” in the sense of
ranges.</p></li>
<li><p>We specifically do not use the names <code>transpose</code> or
<code>transpose_view</code>, since LEWG has advised us that ranges
algorithms may want to claim these names. (One could imagine
“transposing” a range of ranges.)</p></li>
<li><p>We constrain our algorithms only to take vector and matrix
parameters as <code>mdspan</code>. <code>mdspan</code> is not currently
a range, and there are currently no proposals in flight that would make
it a range. Changing <code>mdspan</code> of arbitrary rank to be a range
would require a design for multidimensional iterators. P0009’s coauthors
have not proposed a design, and it has proven challenging to get
compilers to optimize any existing design for multidimensional
iterators.</p></li>
</ul>
<h3 data-number="8.2.2" id="minimal-overlap-with-ranges-is-justified-by-user-convenience"><span class="header-section-number">8.2.2</span> Minimal overlap with ranges
is justified by user convenience<a href="#minimal-overlap-with-ranges-is-justified-by-user-convenience" class="self-link"></a></h3>
<p>The rest of this section answers the second question. The BLAS 2 and
3 algorithms require multiple nested loops, and high-performing
implementations generally need intermediate storage. This would make it
unnatural and difficult to express them in terms of ranges. Only the
BLAS 1 algorithms in our proposal might have a reasonable translation to
ranges algorithms. There, we limit ourselves to the BLAS 1 algorithms in
what follows.</p>
<p>Any rank-1 <code>mdspan</code> <code>x</code> can be translated into
the following range:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> x_range <span class="op">=</span> views<span class="op">::</span>iota<span class="op">(</span><span class="dt">size_t</span><span class="op">(</span><span class="dv">0</span><span class="op">)</span>, x<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span> <span class="op">|</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    views<span class="op">::</span>transform<span class="op">([</span>x<span class="op">]</span> <span class="op">(</span><span class="kw">auto</span> k<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> x<span class="op">[</span>k<span class="op">]</span>; <span class="op">})</span>;</span></code></pre></div>
<p>with specializations possible for <code>mdspan</code> whose layout
mapping’s range is a contiguous or fixed-stride set of offsets. However,
just because code <em>could</em> be written in a certain way doesn’t
mean that it <em>should</em> be. We have ranges even though the language
has <code>for</code> loops; we don’t need to step in the Turing tar-pit
on purpose (see Perlis 1982). Thus, we will analyze the BLAS 1
algorithms in this proposal in the context of the previous section’s
four general criteria.</p>
<p>Our proposal would add 61 new unique names to the C++ Standard
Library. Of those, 16 are BLAS 1 algorithms, while 24 are BLAS 2 and 3
algorithms. The 16 BLAS 1 algorithms fall into three categories:</p>
<ol type="1">
<li><p>Optimization hooks, like <code>copy</code>. As with
<code>memcpy</code>, the fastest implementation may depend closely on
the computer architecture, and may differ significantly from a
straightforward implementation. Some of these algorithms, like
<code>copy</code>, can operate on multidimensional arrays as well,
though it is traditional to list them as BLAS 1 algorithms.</p></li>
<li><p>Floating-point quality-of-implementation hooks, like
<code>vector_sum_of_squares</code>. These give vendors opportunities to
avoid preventable floating-point underflow and overflow (as with
<code>hypot</code>), improve accuracy, and reduce or even avoid parallel
nondeterminism and order dependence of floating-point sums.</p></li>
<li><p>Uncomplicated elementwise algorithms like <code>add</code>,
<code>idx_abs_max</code>, and <code>scale</code>.</p></li>
</ol>
<p>We included the first category mainly because of Criterion (2)
“Opportunity for vendors to provide hardware-specific optimizations,”
and the second mainly because of Criterion (3) (“Opportunity for vendors
to provide quality-of-implementation improvements”). Fast
implementations of algorithms in the first category are not likely to be
simple uses of ranges algorithms.</p>
<p>Algorithms in the second category could be presented as ranges
algorithms, as <code>mdspan</code> algorithms, or as both. The
“iterating over elements” part of those algorithms is not the most
challenging part of their implementation, nor is it what makes an
implementation “high quality.”</p>
<p>Algorithms in the third category could be replaced with a few lines
of C++ that use ranges algorithms. For example, here is a parallel
implementation of <code>idx_abs_max</code>, omitting constraints on
template parameters for simplicity. (Here is a
<a href="https://godbolt.org/z/7eW9ExsKM">Compiler Explorer link</a> to
a working example.)</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Element, <span class="kw">class</span> Extents,</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> Layout, <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">typename</span> Extents<span class="op">::</span>size_type idx_abs_max<span class="op">(</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan<span class="op">&lt;</span>Element, Extents, Layout, Accessor<span class="op">&gt;</span> x<span class="op">)</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> theRange <span class="op">=</span> std<span class="op">::</span>views<span class="op">::</span>iota<span class="op">(</span><span class="dt">size_t</span><span class="op">(</span><span class="dv">0</span><span class="op">)</span>, x<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span> <span class="op">|</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>views<span class="op">::</span>transform<span class="op">([=]</span> <span class="op">(</span><span class="kw">auto</span> k<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> std<span class="op">::</span>abs<span class="op">(</span>x<span class="op">[</span>k<span class="op">])</span>; <span class="op">})</span>;</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> iterOfMax <span class="op">=</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>max_element<span class="op">(</span>std<span class="op">::</span>execution<span class="op">::</span>par_unseq, theRange<span class="op">.</span>begin<span class="op">()</span>, theRange<span class="op">.</span>end<span class="op">())</span>;</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> indexOfMax <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>distance<span class="op">(</span>theRange<span class="op">.</span>begin<span class="op">()</span>, iterOfMax<span class="op">)</span>;</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>  <span class="co">// In GCC 12.1, the return type is __int128.</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="kw">typename</span> Extents<span class="op">::</span>size_type<span class="op">&gt;(</span>indexOfMax<span class="op">)</span>;</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Even though the algorithms in the third category could be implemented
straightforwardly with ranges, we provide them because of Criterion 4
(“User convenience”). Criterion (4) applies to all the algorithms in
this proposal, and particularly to the BLAS 1 algorithms. Matrix
algorithm developers need BLAS 1 and 2 as well as BLAS 3, because matrix
algorithms tend to decompose into vector algorithms. This is true even
of so-called “block” matrix algorithms that have been optimized to use
matrix-matrix operations wherever possible, in order to improve memory
locality. Demmel et al. 1987 (p. 4) explains.</p>
<blockquote>
<p>Block algorithms generally require an unblocked version of the same
algorithm to be available to operate on a single block. Therefore, the
development of the software will fall naturally into two phases: first,
develop unblocked versions of the routines, calling the Level 2 BLAS
wherever possible; then develop blocked versions where possible, calling
the Level 3 BLAS.</p>
</blockquote>
<p>Dongarra et al. 1990 (pp. 12-15) outlines this development process
for the specific example of Cholesky factorization. The Cholesky
factorization algorithm (on p. 14) spends most of its time (for a
sufficiently large input matrix) in matrix-matrix multiplies
(<code>DGEMM</code>), rank-k symmetric matrices updates
(<code>DSYRK</code>, a special case of matrix-matrix multiply), and
triangular solves with multiple “right-hand side” vectors
(<code>DTRSM</code>). However, it still needs an “unblocked” Cholesky
factorization as the blocked factorization’s “base case.” This is called
<code>DLLT</code> in Dongarra et al. 1990 (p. 15), and it uses
<code>DDOT</code>, <code>DSCAL</code> (both BLAS2), and
<code>DGEMV</code> (BLAS 2). In the case of Cholesky factorization, it’s
possible to express the “unblocked” case without using BLAS 1 or 2
operations, by using recursion. This is the approach that LAPACK takes
with the blocked Cholesky factorization
<a href="https://www.netlib.org/lapack/explore-html/d1/d7a/group__double_p_ocomputational_ga2f55f604a6003d03b5cd4a0adcfb74d6.html"><code>DPOTRF</code></a>
and its unblocked base case
<a href="https://www.netlib.org/lapack/explore-html/d1/d7a/group__double_p_ocomputational_gad0718d061dc53c8b0fec6dc3710fab33.html"><code>DPOTRF2</code></a>.
However, even a recursive formulation of most matrix factorizations
needs to use BLAS 1 or 2 operations. For example, the unblocked base
case
<a href="https://www.netlib.org/lapack/explore-html/dd/d9a/group__double_g_ecomputational_gabdd3af29e9f6bbaf4b352341a1e8b464.html"><code>DGETRF2</code></a>
of LAPACK’s blocked LU factorization
<a href="https://www.netlib.org/lapack/explore-html/d3/d6a/dgetrf_8f_source.html"><code>DGETRF</code></a>
needs to invoke vector-vector operations like <code>DSCAL</code>.</p>
<p>In summary, matrix algorithm developers need vector algorithms,
because matrix algorithms decompose into vector algorithms. If our
proposal lacked BLAS 1 algorithms, even simple ones like
<code>add</code> and <code>scale</code>, matrix algorithm developers
would end up writing them anyway.</p>
<h1 data-number="9" id="notation-and-conventions"><span class="header-section-number">9</span> Notation and conventions<a href="#notation-and-conventions" class="self-link"></a></h1>
<h2 data-number="9.1" id="the-blas-uses-fortran-terms"><span class="header-section-number">9.1</span> The BLAS uses Fortran terms<a href="#the-blas-uses-fortran-terms" class="self-link"></a></h2>
<p>The BLAS’ “native” language is Fortran. It has a C binding as well,
but the BLAS Standard and documentation use Fortran terms. Where
applicable, we will call out relevant Fortran terms and highlight
possibly confusing differences with corresponding C++ ideas. Our paper
<a href="https://wg21.link/p1674">P1674</a> (“Evolving a Standard C++
Linear Algebra Library from the BLAS”) goes into more detail on these
issues.</p>
<h2 data-number="9.2" id="we-call-subroutines-functions"><span class="header-section-number">9.2</span> We call “subroutines”
functions<a href="#we-call-subroutines-functions" class="self-link"></a></h2>
<p>Like Fortran, the BLAS distinguishes between functions that return a
value, and subroutines that do not return a value. In what follows, we
will refer to both as “BLAS functions” or “functions.”</p>
<h2 data-number="9.3" id="element-types-and-blas-function-name-prefix"><span class="header-section-number">9.3</span> Element types and BLAS function
name prefix<a href="#element-types-and-blas-function-name-prefix" class="self-link"></a></h2>
<p>The BLAS implements functionality for four different matrix, vector,
or scalar element types:</p>
<ul>
<li><p><code>REAL</code> (<code>float</code> in C++ terms)</p></li>
<li><p><code>DOUBLE PRECISION</code> (<code>double</code> in C++
terms)</p></li>
<li><p><code>COMPLEX</code> (<code>complex&lt;float&gt;</code> in C++
terms)</p></li>
<li><p><code>DOUBLE COMPLEX</code> (<code>complex&lt;double&gt;</code>
in C++ terms)</p></li>
</ul>
<p>The BLAS’ Fortran 77 binding uses a function name prefix to
distinguish functions based on element type:</p>
<ul>
<li><p><code>S</code> for <code>REAL</code> (“single”)</p></li>
<li><p><code>D</code> for <code>DOUBLE PRECISION</code></p></li>
<li><p><code>C</code> for <code>COMPLEX</code></p></li>
<li><p><code>Z</code> for <code>DOUBLE COMPLEX</code></p></li>
</ul>
<p>For example, the four BLAS functions <code>SAXPY</code>,
<code>DAXPY</code>, <code>CAXPY</code>, and <code>ZAXPY</code> all
perform the vector update <code>Y = Y + ALPHA*X</code> for vectors
<code>X</code> and <code>Y</code> and scalar <code>ALPHA</code>, but for
different vector and scalar element types.</p>
<p>The convention is to refer to all of these functions together as
<code>xAXPY</code>. In general, a lower-case <code>x</code> is a
placeholder for all data type prefixes that the BLAS provides. For most
functions, the <code>x</code> is a prefix, but for a few functions like
<code>IxAMAX</code>, the data type “prefix” is not the first letter of
the function name. (<code>IxAMAX</code> is a Fortran function that
returns <code>INTEGER</code>, and therefore follows the old Fortran
implicit naming rule that integers start with <code>I</code>,
<code>J</code>, etc.)</p>
<p>Not all BLAS functions exist for all four data types. These come in
three categories:</p>
<ol type="1">
<li><p>The BLAS provides only real-arithmetic (<code>S</code> and
<code>D</code>) versions of the function, since the function only makes
mathematical sense in real arithmetic.</p></li>
<li><p>The complex-arithmetic versions perform a slightly different
mathematical operation than the real-arithmetic versions, so they have a
different base name.</p></li>
<li><p>The complex-arithmetic versions offer a choice between
nonconjugated or conjugated operations.</p></li>
</ol>
<p>As an example of the second category, the BLAS functions
<code>SASUM</code> and <code>DASUM</code> compute the sums of absolute
values of a vector’s elements. Their complex counterparts
<code>CSASUM</code> and <code>DZASUM</code> compute the sums of absolute
values of real and imaginary components of a vector <code>v</code>, that
is, the sum of <code>abs(real(v[i])) + abs(imag(v[i]))</code> for all
<code>i</code> in the domain of <code>v</code>. The latter operation is
still useful as a vector norm, but it requires fewer arithmetic
operations.</p>
<p>Examples of the third category include the following:</p>
<ul>
<li><p>nonconjugated dot product <code>xDOTU</code> and conjugated dot
product <code>xDOTC</code>; and</p></li>
<li><p>rank-1 symmetric (<code>xGERU</code>) vs. Hermitian
(<code>xGERC</code>) matrix update.</p></li>
</ul>
<p>The conjugate transpose and the (nonconjugated) transpose are the
same operation in real arithmetic (if one considers real arithmetic
embedded in complex arithmetic), but differ in complex arithmetic.
Different applications have different reasons to want either. The C++
Standard includes complex numbers, so a Standard linear algebra library
needs to respect the mathematical structures that go along with complex
numbers.</p>
<h1 data-number="10" id="what-we-exclude-from-the-design"><span class="header-section-number">10</span> What we exclude from the
design<a href="#what-we-exclude-from-the-design" class="self-link"></a></h1>
<h2 data-number="10.1" id="most-functions-not-in-the-reference-blas"><span class="header-section-number">10.1</span> Most functions not in the
Reference BLAS<a href="#most-functions-not-in-the-reference-blas" class="self-link"></a></h2>
<p>The BLAS Standard includes functionality that appears neither in the
<a href="http://www.netlib.org/lapack/explore-html/d1/df9/group__blas.html">Reference
BLAS</a> library, nor in the classic BLAS “level” 1, 2, and 3 papers.
(For history of the BLAS “levels” and a bibliography, see P1417R0. For a
paper describing functions not in the Reference BLAS, see “An updated
set of basic linear algebra subprograms (BLAS),” listed in “Other
references” below.) For example, the BLAS Standard has</p>
<ul>
<li>several new dense functions, like a fused vector update and dot
product;</li>
<li>sparse linear algebra functions, like sparse matrix-vector multiply
and an interface for constructing sparse matrices; and</li>
<li>extended- and mixed-precision dense functions (though we subsume
some of their functionality; see below).</li>
</ul>
<p>Our proposal only includes core Reference BLAS functionality, for the
following reasons:</p>
<ol type="1">
<li><p>Vendors who implement a new component of the C++ Standard Library
will want to see and test against an existing reference
implementation.</p></li>
<li><p>Many applications that use sparse linear algebra also use dense,
but not vice versa.</p></li>
<li><p>The Sparse BLAS interface is a stateful interface that is not
consistent with the dense BLAS, and would need more extensive redesign
to translate into a modern C++ idiom. See discussion in
P1417R0.</p></li>
<li><p>Our proposal subsumes some dense mixed-precision functionality
(see below).</p></li>
</ol>
<p>We have included vector sum-of-squares and matrix norms as
exceptions, for the same reason that we include vector 2-norm: to expose
hooks for quality-of-implementation improvements that avoid underflow or
overflow when computing with floating-point values.</p>
<h2 data-number="10.2" id="lapack-or-related-functionality"><span class="header-section-number">10.2</span> LAPACK or related
functionality<a href="#lapack-or-related-functionality" class="self-link"></a></h2>
<p>The <a href="http://www.netlib.org/lapack/">LAPACK</a> Fortran
library implements solvers for the following classes of mathematical
problems:</p>
<ul>
<li>linear systems,</li>
<li>linear least-squares problems, and</li>
<li>eigenvalue and singular value problems.</li>
</ul>
<p>It also provides matrix factorizations and related linear algebra
operations. LAPACK deliberately relies on the BLAS for good performance;
in fact, LAPACK and the BLAS were designed together. See history
presented in P1417R0.</p>
<p>Several C++ libraries provide slices of LAPACK functionality. Here is
a brief, noninclusive list, in alphabetical order, of some libraries
actively being maintained:</p>
<ul>
<li><a href="http://arma.sourceforge.net/">Armadillo</a>,</li>
<li><a href="https://github.com/boostorg/ublas">Boost.uBLAS</a>,</li>
<li><a href="http://eigen.tuxfamily.org/index.php?title=Main_Page">Eigen</a>,</li>
<li><a href="http://www.simunova.com/de/mtl4/">Matrix Template
Library</a>, and</li>
<li><a href="https://github.com/trilinos/Trilinos/">Trilinos</a>.</li>
</ul>
<p><a href="https://wg21.link/p1417r0">P1417R0</a> gives some history of
C++ linear algebra libraries. The authors of this proposal have <a href="https://www.icl.utk.edu/files/publications/2017/icl-utk-1031-2017.pdf">designed</a>,
<a href="https://github.com/kokkos/kokkos-kernels">written</a>, and <a href="https://github.com/trilinos/Trilinos/tree/master/packages/teuchos/numerics/src">maintained</a>
LAPACK wrappers in C++. Some authors have LAPACK founders as PhD
advisors. Nevertheless, we have excluded LAPACK-like functionality from
this proposal, for the following reasons:</p>
<ol type="1">
<li><p>LAPACK is a Fortran library, unlike the BLAS, which is a
multilanguage standard.</p></li>
<li><p>We intend to support more general element types, beyond the four
that LAPACK supports. It’s much more straightforward to make a C++ BLAS
work for general element types, than to make LAPACK algorithms work
generically.</p></li>
</ol>
<p>First, unlike the BLAS, LAPACK is a Fortran library, not a standard.
LAPACK was developed concurrently with the “level 3” BLAS functions, and
the two projects share contributors. Nevertheless, only the BLAS and not
LAPACK got standardized. Some vendors supply LAPACK implementations with
some optimized functions, but most implementations likely depend heavily
on “reference” LAPACK. There have been a few efforts by LAPACK
contributors to develop C++ LAPACK bindings, from <a href="https://math.nist.gov/lapack++/">Lapack++</a> in pre-templates C++
circa 1993, to the recent <a href="https://www.icl.utk.edu/files/publications/2017/icl-utk-1031-2017.pdf">“C++
API for BLAS and LAPACK”</a>. (The latter shares coauthors with this
proposal.) However, these are still just C++ bindings to a Fortran
library. This means that if vendors had to supply C++ functionality
equivalent to LAPACK, they would either need to start with a Fortran
compiler, or would need to invest a lot of effort in a C++
reimplementation. Mechanical translation from Fortran to C++ introduces
risk, because many LAPACK functions depend critically on details of
floating-point arithmetic behavior.</p>
<p>Second, we intend to permit use of matrix or vector element types
other than just the four types that the BLAS and LAPACK support. This
includes “short” floating-point types, fixed-point types, integers, and
user-defined arithmetic types. Doing this is easier for BLAS-like
operations than for the much more complicated numerical algorithms in
LAPACK. LAPACK strives for a “generic” design (see Jack Dongarra
interview summary in P1417R0), but only supports two real floating-point
types and two complex floating-point types. Directly translating LAPACK
source code into a “generic” version could lead to pitfalls. Many LAPACK
algorithms only make sense for number systems that aim to approximate
real numbers (or their complex extentions). Some LAPACK functions output
error bounds that rely on properties of floating-point arithmetic.</p>
<p>For these reasons, we have left LAPACK-like functionality for future
work. It would be natural for a future LAPACK-like C++ library to build
on our proposal.</p>
<h2 data-number="10.3" id="extended-precision-blas"><span class="header-section-number">10.3</span> Extended-precision BLAS<a href="#extended-precision-blas" class="self-link"></a></h2>
<p>Our interface subsumes some functionality of the Mixed-Precision BLAS
specification (Chapter 4 of the BLAS Standard). For example, users may
multiply two 16-bit floating-point matrices (assuming that a 16-bit
floating-point type exists) and accumulate into a 32-bit floating-point
matrix, just by providing a 32-bit floating-point matrix as output.
Users may specify the precision of a dot product result. If it is
greater than the input vectors’ element type precisions (e.g.,
<code>double</code> vs. <code>float</code>), then this effectively
performs accumulation in higher precision. Our proposal imposes semantic
requirements on some functions, like <code>vector_norm2</code>, to
behave in this way.</p>
<p>However, we do not include the “Extended-Precision BLAS” in this
proposal. The BLAS Standard lets callers decide at run time whether to
use extended precision floating-point arithmetic for internal
evaluations. We could support this feature at a later time.
Implementations of our interface also have the freedom to use more
accurate evaluation methods than typical BLAS implementations. For
example, it is possible to make floating-point sums completely <a href="https://bebop.cs.berkeley.edu/reproblas/">independent of parallel
evaluation order</a>.</p>
<h2 data-number="10.4" id="arithmetic-operators-and-associated-expression-templates"><span class="header-section-number">10.4</span> Arithmetic operators and
associated expression templates<a href="#arithmetic-operators-and-associated-expression-templates" class="self-link"></a></h2>
<p>Our proposal omits arithmetic operators on matrices and vectors. We
do so for the following reasons:</p>
<ol type="1">
<li><p>We propose a low-level, minimal interface.</p></li>
<li><p><code>operator*</code> could have multiple meanings for matrices
and vectors. Should it mean elementwise product (like
<code>valarray</code>) or matrix product? Should libraries reinterpret
“vector times vector” as a dot product (row vector times column vector)?
We prefer to let a higher-level library decide this, and make everything
explicit at our lower level.</p></li>
<li><p>Arithmetic operators require defining the element type of the
vector or matrix returned by an expression. Functions let users specify
this explicitly, and even let users use different output types for the
same input types in different expressions.</p></li>
<li><p>Arithmetic operators may require allocation of temporary matrix
or vector storage. This prevents use of nonowning data
structures.</p></li>
<li><p>Arithmetic operators strongly suggest expression templates. These
introduce problems such as dangling references and aliasing.</p></li>
</ol>
<p>Our goal is to propose a low-level interface. Other libraries, such
as that proposed by <a href="https://wg21.link/p1385r6">P1385R6</a>,
could use our interface to implement overloaded arithmetic for matrices
and vectors. A constrained, function-based, BLAS-like interface builds
incrementally on the many years of BLAS experience.</p>
<p>Arithmetic operators on matrices and vectors would require the
library, not necessarily the user, to specify the element type of an
expression’s result. This gets tricky if the terms have mixed element
types. For example, what should the element type of the result of the
vector sum <code>x + y</code> be, if <code>x</code> has element type
<code>complex&lt;float&gt;</code> and <code>y</code> has element type
<code>double</code>? It’s tempting to use <code>common_type_t</code>,
but <code>common_type_t&lt;complex&lt;float&gt;, double&gt;</code> is
<code>complex&lt;float&gt;</code>. This loses precision. Some users may
want <code>complex&lt;double&gt;</code>; others may want
<code>complex&lt;long double&gt;</code> or something else, and others
may want to choose different types in the same program.</p>
<p>P1385R6 lets users customize the return type of such arithmetic
expressions. However, different algorithms may call for the same
expression with the same inputs to have different output types. For
example, iterative refinement of linear systems <code>Ax=b</code> can
work either with an extended-precision intermediate residual vector
<code>r = b - A*x</code>, or with a residual vector that has the same
precision as the input linear system. Each choice produces a different
algorithm with different convergence characteristics, per-iteration run
time, and memory requirements. Thus, our library lets users specify the
result element type of linear algebra operations explicitly, by calling
a named function that takes an output argument explicitly, rather than
an arithmetic operator.</p>
<p>Arithmetic operators on matrices or vectors may also need to allocate
temporary storage. Users may not want that. When LAPACK’s developers
switched from Fortran 77 to a subset of Fortran 90, their users rejected
the option of letting LAPACK functions allocate temporary storage on
their own. Users wanted to control memory allocation. Also, allocating
storage precludes use of nonowning input data structures like
<code>mdspan</code>, that do not know how to allocate.</p>
<p>Arithmetic expressions on matrices or vectors strongly suggest
expression templates, as a way to avoid allocation of temporaries and to
fuse computational kernels. They do not <em>require</em> expression
templates. For example, <code>valarray</code> offers overloaded
operators for vector arithmetic, but the Standard lets implementers
decide whether to use expression templates. However, all of the current
C++ linear algebra libraries that we mentioned above have some form of
expression templates for overloaded arithmetic operators, so users will
expect this and rely on it for good performance. This was, indeed, one
of the major complaints about initial implementations of
<code>valarray</code>: its lack of mandate for expression templates
meant that initial implementations were slow, and thus users did not
want to rely on it. (See Josuttis 1999, p. 547, and Vandevoorde and
Josuttis 2003, p. 342, for a summary of the history. Fortran has an
analogous issue, in which (under certain conditions) it is
implementation defined whether the run-time environment needs to copy
noncontiguous slices of an array into contiguous temporary storage.)</p>
<p>Expression templates work well, but have issues. Our papers
<a href="https://wg21.link/p1417r0">P1417R0</a> and “Evolving a Standard
C++ Linear Algebra Library from the BLAS”
<a href="https://wg21.link/p1674">(P1674)</a> give more detail on these
concerns. A particularly troublesome one is that C++ <code>auto</code>
type deduction makes it easy for users to capture expressions before the
expression templates system has the chance to evaluate them and write
the result into the output. For matrices and vectors with container
semantics, this makes it easy to create dangling references. Users might
not realize that they need to assign expressions to named types before
actual work and storage happen. <a href="https://eigen.tuxfamily.org/dox/TopicPitfalls.html">Eigen’s
documentation</a> describes this common problem.</p>
<p>Our <code>scaled</code>, <code>conjugated</code>,
<code>transposed</code>, and <code>conjugate_transposed</code> functions
make use of one aspect of expression templates, namely modifying the
<code>mdspan</code> array access operator. However, we intend these
functions for use only as in-place modifications of arguments of a
function call. Also, when modifying <code>mdspan</code>, these functions
merely view the same data that their input <code>mdspan</code> views.
They introduce no more potential for dangling references than
<code>mdspan</code> itself. The use of views like <code>mdspan</code> is
self-documenting; it tells users that they need to take responsibility
for scope of the viewed data.</p>
<h2 data-number="10.5" id="banded-matrix-layouts"><span class="header-section-number">10.5</span> Banded matrix layouts<a href="#banded-matrix-layouts" class="self-link"></a></h2>
<p>This proposal omits banded matrix types. It would be easy to add the
required layouts and specializations of algorithms later. The packed and
unpacked symmetric and triangular layouts in this proposal cover the
major concerns that would arise in the banded case, like nonstrided and
nonunique layouts, and matrix types that forbid access to some
multi-indices in the Cartesian product of extents.</p>
<h2 data-number="10.6" id="tensors"><span class="header-section-number">10.6</span> Tensors<a href="#tensors" class="self-link"></a></h2>
<p>We exclude tensors from this proposal, for the following reasons.
First, tensor libraries naturally build on optimized dense linear
algebra libraries like the BLAS, so a linear algebra library is a good
first step. Second, <code>mdspan</code> has natural use as a low-level
representation of dense tensors, so we are already partway there. Third,
even simple tensor operations that naturally generalize the BLAS have
infintely many more cases than linear algebra. It’s not clear to us
which to optimize. Fourth, even though linear algebra is a special case
of tensor algebra, users of linear algebra have different interface
expectations than users of tensor algebra. Thus, it makes sense to have
two separate interfaces.</p>
<h2 data-number="10.7" id="explicit-support-for-asynchronous-return-of-scalar-values"><span class="header-section-number">10.7</span> Explicit support for
asynchronous return of scalar values<a href="#explicit-support-for-asynchronous-return-of-scalar-values" class="self-link"></a></h2>
<p>After we presented revision 2 of this paper, LEWG asked us to
consider support for discrete graphics processing units (GPUs). GPUs
have two features of interest here. First, they might have memory that
is not accessible from ordinary C++ code, but could be accessed in a
standard algorithm (or one of our proposed algorithms) with the right
implementation-specific <code>ExecutionPolicy</code>. (For instance, a
policy could say “run this algorithm on the GPU.”) Second, they might
execute those algorithms asynchronously. That is, they might write to
output arguments at some later time after the algorithm invocation
returns. This would imply different interfaces in some cases. For
instance, a hypothetical asynchronous vector 2-norm might write its
scalar result via a pointer to GPU memory, instead of returning the
result “on the CPU.”</p>
<p>Nothing in principle prevents <code>mdspan</code> from viewing memory
that is inaccessible from ordinary C++ code. This is a major feature of
the <code>Kokkos::View</code> class from the <a href="https://github.com/kokkos/kokkos">Kokkos library</a>, and
<code>Kokkos::View</code> directly inspired <code>mdspan</code>. The C++
Standard does not currently define how such memory behaves, but
implementations could define its behavior and make it work with
<code>mdspan</code>. This would, in turn, let implementations define our
algorithms to operate on such memory efficiently, if given the right
implementation-specific <code>ExecutionPolicy</code>.</p>
<p>Our proposal excludes algorithms that might write to their output
arguments at some time after after the algorithm returns. First, LEWG
insisted that our proposed algorithms that compute a scalar result, like
<code>vector_norm2</code>, return that result in the manner of
<code>reduce</code>, rather than writing the result to an output
reference or pointer. (Previous revisions of our proposal used the
latter interface pattern.) Second, it’s not clear whether writing a
scalar result to a pointer is the right interface for asynchronous
algorithms. Follow-on proposals to <a href="https://wg21.link/p0443R14">Executors (P0443R14)</a> include
asynchronous algorithms, but none of these suggest returning results
asynchronously by pointer. Our proposal deliberately imitates the
existing standard algorithms. Right now, we have no standard
asynchronous algorithms to imitate.</p>
<h1 data-number="11" id="design-justification"><span class="header-section-number">11</span> Design justification<a href="#design-justification" class="self-link"></a></h1>
<p>We take a step-wise approach. We begin with core BLAS dense linear
algebra functionality. We then deviate from that only as much as
necessary to get algorithms that behave as much as reasonable like the
existing C++ Standard Library algorithms. Future work or collaboration
with other proposals could implement a higher-level interface.</p>
<p>Please refer to our papers “Evolving a Standard C++ Linear Algebra
Library from the BLAS” <a href="https://wg21.link/p1674">(P1674)</a> and
“Historical lessons for C++ linear algebra library standardization”
<a href="https://wg21.link/p1417">(P1417)</a> They will give details and
references for many of the points that we summarize here.</p>
<h2 data-number="11.1" id="we-do-not-require-using-the-blas-library-or-any-particular-back-end"><span class="header-section-number">11.1</span> We do not require using the
BLAS library or any particular “back-end”<a href="#we-do-not-require-using-the-blas-library-or-any-particular-back-end" class="self-link"></a></h2>
<p>Our proposal is inspired by and extends the dense BLAS interface. A
natural implementation might look like this:</p>
<ol type="1">
<li><p>wrap an existing C or Fortran BLAS library,</p></li>
<li><p>hope that the BLAS library is optimized, and then</p></li>
<li><p>extend the wrapper to include straightforward Standard C++
implementations of P1673’s algorithms for matrix and vector value types
and data layouts that the BLAS does not support.</p></li>
</ol>
<p>P1674 describes the process of writing such an implementation.
However, P1673 does not require implementations to wrap the BLAS. In
particular, P1673 does not specify a “back-end” C-style interface that
would let users or implementers “swap out” different BLAS libraries.
Here are some reasons why we made this choice.</p>
<p>First, it’s possible to write an optimized implementation entirely in
Standard C++, without calling external C or Fortran functions. For
example, one can write a cache-blocked matrix-matrix multiply
implementationen entirely in Standard C++.</p>
<p>Second, different vendors may have their own libraries that support
matrix and vector value types and/or layouts beyond what the standard
dense BLAS supports. For example, they may have C functions for
mixed-precision matrix-matrix multiply, like BLIS’ <code>bli_gemm</code>
<a href="https://github.com/flame/blis/blob/master/examples/oapi/11gemm_md.c">(example
here)</a>, or NVIDIA’s <code>cublasGemmEx</code>
<a href="https://docs.nvidia.com/cuda/cublas/index.html#cublas-GemmEx">(example
here)</a>.</p>
<p>Third, just because a C or Fortran BLAS library can be found, doesn’t
mean that it’s optimized at all or optimized well. For example, many
Linux distributions have a BLAS software package that is built by
compiling the Reference BLAS. This will give poor performance for BLAS 3
operations. Even “optimized” vendor BLAS libraries may not optimize all
cases. Release notes even for recent versions show performance
improvements.</p>
<p>In summary: While a natural way to implement this proposal would be
to wrap an existing C or Fortran BLAS library, we do not want to require
this. Thus, we do not specify a “back-end” C-style interface.</p>
<h2 data-number="11.2" id="why-use-mdspan"><span class="header-section-number">11.2</span> Why use <code>mdspan</code>?<a href="#why-use-mdspan" class="self-link"></a></h2>
<h3 data-number="11.2.1" id="view-of-a-multidimensional-array"><span class="header-section-number">11.2.1</span> View of a multidimensional
array<a href="#view-of-a-multidimensional-array" class="self-link"></a></h3>
<p>The BLAS operates on what C++ programmers might call views of
multidimensional arrays. Users of the BLAS can store their data in
whatever data structures they like, and handle their allocation and
lifetime as they see fit, as long as the data have a BLAS-compatible
memory layout.</p>
<p>The corresponding C++ data structure is <code>mdspan</code>. This
class encapsulates the large number of pointer and integer arguments
that BLAS functions take, that represent views of matrices and vectors.
Using <code>mdspan</code> in the C++ interface reduce the number of
arguments and avoids common errors, like mixing up the order of
arguments. It supports all the array memory layouts that the BLAS
supports, including row major and column major. It also expresses the
same data ownership model that the BLAS expresses. Users may manage
allocation and deallocation however they wish. In addition,
<code>mdspan</code> lets our algorithms exploit any dimensions known at
compile time.</p>
<h3 data-number="11.2.2" id="ease-of-use"><span class="header-section-number">11.2.2</span> Ease of use<a href="#ease-of-use" class="self-link"></a></h3>
<p>The <code>mdspan</code> class’ layout and accessor policies let us
simplify our interfaces, by encapsulating transpose, conjugate, and
scalar arguments. Features of <code>mdspan</code> make implementing
BLAS-like algorithms much less error prone and easier to read. These
include its encapsulation of matrix indexing and its built-in “slicing”
capabilities via <code>submdspan</code>.</p>
<h3 data-number="11.2.3" id="blas-and-mdspan-are-low-level"><span class="header-section-number">11.2.3</span> BLAS and <code>mdspan</code>
are low level<a href="#blas-and-mdspan-are-low-level" class="self-link"></a></h3>
<p>The BLAS is low level; it imposes no mathematical meaning on
multidimensional arrays. This gives users the freedom to develop
mathematical libraries with the semantics they want. Similarly,
<code>mdspan</code> is just a view of a multidimensional array; it has
no mathematical meaning on its own.</p>
<p>We mention this because “matrix,” “vector,” and “tensor” are
mathematical ideas that mean more than just arrays of numbers. This is
more than just a theoretical concern. Some BLAS functions operate on
“triangular,” “symmetric,” or “Hermitian” matrices, but they do not
assert that a matrix has any of these mathematical properties. Rather,
they only read only one side of the matrix (the lower or upper
triangle), and compute as if the other side of the matrix satisfies the
mathematical property. A key feature of the BLAS and libraries that
build on it, like LAPACK, is that they can operate on the matrix’s data
in place. These operations change both the matrix’s mathematical
properties and its representation in memory. For example, one might have
an N x N array representing a matrix that is symmetric in theory, but
computed and stored in a way that might not result in exactly symmetric
data. In order to solve linear systems with this matrix, one might give
the array to LAPACK’s <code>xSYTRF</code> to compute an <span class="math inline"><em>L</em><em>D</em><em>L</em><sup><em>T</em></sup></span>
factorization, asking <code>xSYTRF</code> only to access the array’s
lower triangle. If <code>xSYTRF</code> finishes successfully, it has
overwritten the lower triangle of its input with a representation of
both the lower triangular factor L and the block diagonal matrix D, as
computed assuming that the matrix is the sum of the lower triangle and
the transpose of the lower triangle. The resulting N x N array no longer
represents a symmetric matrix. Rather, it contains part of the
representation of a <span class="math inline"><em>L</em><em>D</em><em>L</em><sup><em>T</em></sup></span>
factorization of the matrix. The upper triangle still contains the
original input matrix’s data. One may then solve linear systems by
giving <code>xSYTRS</code> the lower triangle, along with other output
of <code>xSYTRF</code>.</p>
<p>The point of this example is that a “symmetric matrix class” is the
wrong way to model this situation. There’s an N x N array, whose
mathematical interpretation changes with each in-place operation
performed on it. The low-level <code>mdspan</code> data structure
carries no mathematical properties in itself, so it models this
situation better.</p>
<h3 data-number="11.2.4" id="hook-for-future-expansion"><span class="header-section-number">11.2.4</span> Hook for future expansion<a href="#hook-for-future-expansion" class="self-link"></a></h3>
<p>The <code>mdspan</code> class treats its layout as an extension
point. This lets our interface support layouts beyond what the BLAS
Standard permits. The accessor extension point offers us a hook for
future expansion to support heterogeneous memory spaces. (This is a key
feature of <code>Kokkos::View</code>, the data structure that inspired
<code>mdspan</code>.) In addition, using <code>mdspan</code> will make
it easier for us to add an efficient “batched” interface in future
proposals.</p>
<h3 data-number="11.2.5" id="generic-enough-to-replace-a-multidimensional-array-concept"><span class="header-section-number">11.2.5</span> Generic enough to replace a
“multidimensional array concept”<a href="#generic-enough-to-replace-a-multidimensional-array-concept" class="self-link"></a></h3>
<p>LEWGI requested in the 2019 Cologne meeting that we explore using a
concept instead of <code>mdspan</code> to define the arguments for the
linear algebra functions. This would mean that instead of having our
functions take <code>mdspan</code> parameters, they would be generic on
one or more suitably constrained multidimensional array types. The
constraints would form a “multidimensional array concept.”</p>
<p>We investigated this option, and rejected it, for the following
reasons.</p>
<ol type="1">
<li><p>Our proposal uses enough features of <code>mdspan</code> that any
concept generally applicable to all functions we propose would largely
replicate the definition of <code>mdspan</code>.</p></li>
<li><p>This proposal could support most multidimensional array types, if
the array types just made themselves convertible to
<code>mdspan</code>.</p></li>
<li><p>We could always generalize our algorithms later.</p></li>
<li><p>Any multidimensional array concept would need revision in the
light of <a href="https://wg21.link/p2128r6">P2128R6</a>.</p></li>
</ol>
<p>This proposal refers to almost all of <code>mdspan</code>’s features,
including <code>extents</code>, layouts, and accessors. We expect
implementations to use all of them for optimizations, for example to
extract the scaling factor from the return value of <code>scaled</code>
in order to call an optimized BLAS library directly.</p>
<p>Suppose that a general customization point <code>get_mdspan</code>
exists, that takes a reference to a multidimensional array type and
returns an <code>mdspan</code> that views the array. Then, our proposal
could support most multidimensional array types. “Most” includes all
such types that refer to a subset of a contiguous span of memory.</p>
<p>Requiring that a multidimensional array refer to a subset of a
contiguous span of memory would exclude multidimensional array types
that have a noncontiguous backing store, such as a <code>map</code>. If
we later wanted to support such types, we could always generalize our
algorithms later.</p>
<p>Finally, any existing multidimensional array concept would need
revision in the light of
<a href="https://wg21.link/p2128r6">P2128R6</a>, which has been voted
into the C++ Standard draft. P2128 lets <code>operator[]</code> take
multiple parameters. The version of mdspan which was voted into the C++
Standard draft uses <code>operator[]</code> instead of
<code>operator()</code> as the array access operator.</p>
<p>After further discussion at the 2019 Belfast meeting, LEWGI accepted
our position that having our algorithms take <code>mdspan</code> instead
of template parameters constrained by a multidimensional array concept
would be fine for now.</p>
<h2 data-number="11.3" id="function-argument-aliasing-and-zero-scalar-multipliers"><span class="header-section-number">11.3</span> Function argument aliasing and
zero scalar multipliers<a href="#function-argument-aliasing-and-zero-scalar-multipliers" class="self-link"></a></h2>
<p>Summary:</p>
<ol type="1">
<li><p>The BLAS Standard forbids aliasing any input (read-only) argument
with any output (write-only or read-and-write) argument.</p></li>
<li><p>The BLAS uses <code>INTENT(INOUT)</code> (read-and-write)
arguments to express “updates” to a vector or matrix. By contrast, C++
Standard algorithms like <code>transform</code> take input and output
iterator ranges as different parameters, but may let input and output
ranges be the same.</p></li>
<li><p>The BLAS uses the values of scalar multiplier arguments (“alpha”
or “beta”) of vectors or matrices at run time, to decide whether to
treat the vectors or matrices as write only. This matters both for
performance and semantically, assuming IEEE floating-point
arithmetic.</p></li>
<li><p>We decide separately, based on the category of BLAS function, how
to translate <code>INTENT(INOUT)</code> arguments into a C++ idiom:</p>
<ol type="a">
<li><p>For triangular solve and triangular multiply, in-place behavior
is essential for computing matrix factorizations in place, without
requiring extra storage proportional to the input matrix’s dimensions.
However, in-place functions may hinder implementations’ use of some
forms of parallelism. Thus, we have both not-in-place and in-place
overloads. Both take an optional <code>ExecutionPolicy&amp;&amp;</code>,
as some forms of parallelism (e.g., vectorization) may still be
effective with in-place operations.</p></li>
<li><p>Else, if the BLAS function unconditionally updates (like
<code>xGER</code>), we retain read-and-write behavior for that
argument.</p></li>
<li><p>Else, if the BLAS function uses a scalar <code>beta</code>
argument to decide whether to read the output argument as well as write
to it (like <code>xGEMM</code>), we provide two versions: a write-only
version (as if <code>beta</code> is zero), and a read-and-write version
(as if <code>beta</code> is nonzero).</p></li>
</ol></li>
</ol>
<p>For a detailed analysis, please see our paper “Evolving a Standard
C++ Linear Algebra Library from the BLAS”
<a href="https://wg21.link/p1674">(P1674)</a>.</p>
<h2 data-number="11.4" id="support-for-different-matrix-layouts"><span class="header-section-number">11.4</span> Support for different matrix
layouts<a href="#support-for-different-matrix-layouts" class="self-link"></a></h2>
<p>Summary:</p>
<ol type="1">
<li><p>The dense BLAS supports several different dense matrix “types.”
Type is a mixture of “storage format” (e.g., packed, banded) and
“mathematical property” (e.g., symmetric, Hermitian,
triangular).</p></li>
<li><p>Some “types” can be expressed as custom <code>mdspan</code>
layouts. Other types actually represent algorithmic constraints: for
instance, what entries of the matrix the algorithm is allowed to
access.</p></li>
<li><p>Thus, a C++ BLAS wrapper cannot overload on matrix “type” simply
by overloading on <code>mdspan</code> specialization. The wrapper must
use different function names, tags, or some other way to decide what the
matrix type is.</p></li>
</ol>
<p>For more details, including a list and description of the matrix
“types” that the dense BLAS supports, please see our paper “Evolving a
Standard C++ Linear Algebra Library from the BLAS”
<a href="https://wg21.link/p1674">(P1674)</a>.</p>
<p>A C++ linear algebra library has a few possibilities for
distinguishing the matrix “type”:</p>
<ol type="1">
<li><p>It could imitate the BLAS, by introducing different function
names, if the layouts and accessors do not sufficiently describe the
arguments.</p></li>
<li><p>It could introduce a hierarchy of higher-level classes for
representing linear algebra objects, use <code>mdspan</code> (or
something like it) underneath, and write algorithms to those
higher-level classes.</p></li>
<li><p>It could use the layout and accessor types in <code>mdspan</code>
simply as tags to indicate the matrix “type.” Algorithms could
specialize on those tags.</p></li>
</ol>
<p>We have chosen Approach 1. Our view is that a BLAS-like interface
should be as low-level as possible. Approach 2 is more like a “Matlab in
C++”; a library that implements this could build on our proposal’s
lower-level library. Approach 3 <em>sounds</em> attractive. However,
most BLAS matrix “types” do not have a natural representation as
layouts. Trying to hack them in would pollute <code>mdspan</code> – a
simple class meant to be easy for the compiler to optimize – with extra
baggage for representing what amounts to sparse matrices. We think that
BLAS matrix “type” is better represented with a higher-level library
that builds on our proposal.</p>
<h2 data-number="11.5" id="interpretation-of-lower-upper-triangular"><span class="header-section-number">11.5</span> Interpretation of “lower /
upper triangular”<a href="#interpretation-of-lower-upper-triangular" class="self-link"></a></h2>
<h3 data-number="11.5.1" id="triangle-refers-to-what-part-of-the-matrix-is-accessed"><span class="header-section-number">11.5.1</span> Triangle refers to what part
of the matrix is accessed<a href="#triangle-refers-to-what-part-of-the-matrix-is-accessed" class="self-link"></a></h3>
<p>The triangular, symmetric, and Hermitian algorithms in this proposal
all take a <code>Triangle</code> tag that specifies whether the
algorithm should access the upper or lower triangle of the matrix. This
has the same function as the <code>UPLO</code> argument of the
corresponding BLAS routines. The upper or lower triangular argument only
refers to what part of the matrix the algorithm will access. The “other
triangle” of the matrix need not contain useful data. For example, with
the symmetric algorithms, <code>A[j, i]</code> need not equal
<code>A[i, j]</code> for any <code>i</code> and <code>j</code> in the
domain of <code>A</code> with <code>i</code> not equal to
<code>j</code>. The algorithm just accesses one triangle and interprets
the other triangle as the result of flipping the accessed triangle over
the diagonal.</p>
<p>This “interpretation” approach to representing triangular matrices is
critical for matrix factorizations. For example, LAPACK’s LU
factorization (<code>xGETRF</code>) overwrites a matrix A with both its
L (lower triangular, implicitly represented diagonal of all ones) and U
(upper triangular, explicitly stored diagonal) factors. Solving linear
systems Ax=b with this factorization, as LAPACK’s <code>xGETRS</code>
routine does, requires solving first a linear system with the upper
triangular matrix U, and then solving a linear system with the lower
triangular matrix L. If the BLAS required that the “other triangle” of a
triangular matrix had all zero elements, then LU factorization would
require at least twice the storage. For symmetric and Hermitian
matrices, only accessing the matrix’s elements nonredundantly ensures
that the matrix remains mathematically symmetric resp. Hermitian, even
in the presence of rounding error.</p>
<h3 data-number="11.5.2" id="blas-applies-uplo-to-original-matrix-we-apply-triangle-to-transformed-matrix"><span class="header-section-number">11.5.2</span> BLAS applies UPLO to
original matrix; we apply Triangle to transformed matrix<a href="#blas-applies-uplo-to-original-matrix-we-apply-triangle-to-transformed-matrix" class="self-link"></a></h3>
<p>The BLAS routines that take an <code>UPLO</code> argument generally
also take a <code>TRANS</code> argument. The <code>TRANS</code> argument
says whether to apply the matrix, its transpose, or its conjugate
transpose. The BLAS applies the <code>UPLO</code> argument to the
“original” matrix, not to the transposed matrix. For example, if
<code>TRANS=&#39;T&#39;</code> or <code>TRANS=&#39;C&#39;</code>, <code>UPLO=&#39;U&#39;</code>
means the routine will access the upper triangle of the matrix, not the
upper triangle of the matrix’s transpose.</p>
<p>Our proposal takes the opposite approach. It applies
<code>Triangle</code> to the input matrix, which may be the result of a
transformation such as <code>transposed</code> or
<code>conjugate_transposed</code>. For example, if <code>Triangle</code>
is <code>upper_triangle_t</code>, the algorithm will always access the
matrix for <code>i,j</code> in its domain with <code>i</code> ≤
<code>j</code> (or <code>i</code> strictly less than <code>j</code>, if
the algorithm takes a <code>Diagonal</code> tag and
<code>Diagonal</code> is <code>implicit_unit_diagonal_t</code>). If the
input matrix is <code>transposed(A)</code> for a
<code>layout_left</code> <code>mdspan</code> <code>A</code>, this means
that the algorithm will access the upper triangle of
<code>transposed(A)</code>, which is actually the <em>lower</em>
triangle of <code>A</code>.</p>
<p>We took this approach because our interface permits arbitrary
layouts, with possibly arbitrary nesting of layout transformations. This
comes from <code>mdspan</code>’s design itself, not even necessarily
from our proposal. For example, users might define
<code>antitranspose(A)</code>, that flips indices over the antidiagonal
(the “other diagonal” that goes from the lower left to the upper right
of the matrix, instead of from the upper left to the lower right).
Layout transformations need not even be one-to-one, because layouts
themselves need not be (hence <code>is_unique</code>). Since it’s not
possible to “undo” a general layout, there’s no way to get back to the
“original matrix.”</p>
<p>Our approach, while not consistent with the BLAS, is internally
consistent. <code>Triangle</code> always has a clear meaning, no matter
what transformations users apply to the input. Layout transformations
like <code>transposed</code> have the same interpretation for all the
matrix algorithms, whether for general, triangular, symmetric, or
Hermitian matrices. This interpretation is consistent with the standard
meaning of <code>mdspan</code> layouts.</p>
<p>C BLAS implementations already apply layout transformations like this
so that they can use an existing column-major Fortran BLAS to implement
operations on matrices with different layouts. For example, the
transpose of an <code>M</code> x <code>N</code> <code>layout_left</code>
matrix is just the same data, viewed as an <code>N</code> x
<code>M</code> <code>layout_right</code> matrix. Thus,
<code>transposed</code> is consistent with current practice. In fact,
<code>transposed</code> need not use a special
<code>layout_transpose</code>, if it knows how to reinterpret the input
layout.</p>
<h3 data-number="11.5.3" id="summary"><span class="header-section-number">11.5.3</span> Summary<a href="#summary" class="self-link"></a></h3>
<ol type="1">
<li><p>BLAS applies <code>UPLO</code> to the original matrix, before any
transposition. Our proposal applies <code>Triangle</code> to the
transformed matrix, after any transposition.</p></li>
<li><p>Our approach is the only reasonable way to handle the full
generality of user-defined layouts and layout transformations.</p></li>
</ol>
<h2 data-number="11.6" id="over--and-underflow-wording-for-vector-2-norm"><span class="header-section-number">11.6</span> Over- and underflow wording
for vector 2-norm<a href="#over--and-underflow-wording-for-vector-2-norm" class="self-link"></a></h2>
<p>SG6 recommended to us at Belfast 2019 to change the special overflow
/ underflow wording for <code>vector_norm2</code> to imitate the BLAS
Standard more closely. The BLAS Standard does say something about
overflow and underflow for vector 2-norms. We reviewed this wording and
conclude that it is either a nonbinding quality of implementation (QoI)
recommendation, or too vaguely stated to translate directly into C++
Standard wording. Thus, we removed our special overflow / underflow
wording. However, the BLAS Standard clearly expresses the intent that
implementations document their underflow and overflow guarantees for
certain functions, like vector 2-norms. The C++ Standard requires
documentation of “implementation-defined behavior.” Therefore, we added
language to our proposal that makes “any guarantees regarding overflow
and underflow” of those certain functions “implementation-defined.”</p>
<p>Previous versions of this paper asked implementations to compute
vector 2-norms “without undue overflow or underflow at intermediate
stages of the computation.” “Undue” imitates existing C++ Standard
wording for <code>hypot</code>. This wording hints at the stricter
requirements in F.9 (normative, but optional) of the C Standard for math
library functions like <code>hypot</code>, without mandating those
requirements. In particular, paragraph 9 of F.9 says:</p>
<blockquote>
<p>Whether or when library functions raise an undeserved “underflow”
floating-point exception is unspecified. Otherwise, as implied by F.7.6,
the <strong>&lt;math.h&gt;</strong> functions do not raise spurious
floating-point exceptions (detectable by the user) [including the
“overflow” exception discussed in paragraph 6], other than the “inexact”
floating-point exception.</p>
</blockquote>
<p>However, these requirements are for math library functions like
<code>hypot</code>, not for general algorithms that return
floating-point values. SG6 did not raise a concern that we should treat
<code>vector_norm2</code> like a math library function; their concern
was that we imitate the BLAS Standard’s wording.</p>
<p>The BLAS Standard says of several operations, including vector
2-norm: “Here are the exceptional routines where we ask for particularly
careful implementations to avoid unnecessary over/underflows, that could
make the output unnecessarily inaccurate or unreliable” (p. 35).</p>
<p>The BLAS Standard does not define phrases like “unnecessary
over/underflows.” The likely intent is to avoid naïve implementations
that simply add up the squares of the vector elements. These would
overflow even if the norm in exact arithmetic is significantly less than
the overflow threshold. The POSIX Standard (IEEE Std 1003.1-2017)
analogously says that <code>hypot</code> must “take precautions against
overflow during intermediate steps of the computation.”</p>
<p>The phrase “precautions against overflow” is too vague for us to
translate into a requirement. The authors likely meant to exclude naïve
implementations, but not require implementations to know whether a
result computed in exact arithmetic would overflow or underflow. The
latter is a special case of computing floating-point sums exactly, which
is costly for vectors of arbitrary length. While it would be a useful
feature, it is difficult enough that we do not want to require it,
especially since the BLAS Standard itself does not. The implementation
of vector 2-norms in the Reference BLAS included with LAPACK 3.10.0
partitions the running sum of squares into three different accumulators:
one for big values (that might cause the sum to overflow without
rescaling), one for small values (that might cause the sum to underflow
without rescaling), and one for the remaining “medium” values. (See
Anderson 2017.) Earlier implementations merely rescaled by the current
maximum absolute value of all the vector entries seen thus far. (See
Blue 1978.) Implementations could also just compute the sum of squares
in a straightforward loop, then check floating-point status flags for
underflow or overflow, and recompute if needed.</p>
<p>For all of the functions listed on p. 35 of the BLAS Standard as
needing “particularly careful implementations,” <em>except</em> vector
norm, the BLAS Standard has an “Advice to implementors” section with
extra accuracy requirements. The BLAS Standard does have an “Advice to
implementors” section for matrix norms (see Section 2.8.7, p. 69), which
have similar over- and underflow concerns as vector norms. However, the
Standard merely states that “[h]igh-quality implementations of these
routines should be accurate” and should document their accuracy, and
gives examples of “accurate implementations” in LAPACK.</p>
<p>The BLAS Standard never defines what “Advice to implementors” means.
However, the BLAS Standard shares coauthors and audience with the
Message Passing Interface (MPI) Standard, which defines “Advice to
implementors” as “primarily commentary to implementors” and permissible
to skip (see e.g., MPI 3.0, Section 2.1, p. 9). We thus interpret
“Advice to implementors” in the BLAS Standard as a nonbinding quality of
implementation (QoI) recommendation.</p>
<h2 data-number="11.7" id="constraining-matrix-and-vector-element-types-and-scalars"><span class="header-section-number">11.7</span> Constraining matrix and vector
element types and scalars<a href="#constraining-matrix-and-vector-element-types-and-scalars" class="self-link"></a></h2>
<h3 data-number="11.7.1" id="introduction"><span class="header-section-number">11.7.1</span> Introduction<a href="#introduction" class="self-link"></a></h3>
<p>The BLAS only accepts four different types of scalars and matrix and
vector elements. In C++ terms, these correspond to <code>float</code>,
<code>double</code>, <code>complex&lt;float&gt;</code>, and
<code>complex&lt;double&gt;</code>. The algorithms we propose generalize
the BLAS by accepting any matrix, vector, or scalar element types that
make sense for each algorithm. Those may be built-in types, like
floating-point numbers or integers, or they may be custom types. Those
custom types might not behave like conventional real or complex numbers.
For example, quaternions have noncommutative multiplication
(<code>a * b</code> might not equal <code>b * a</code>), polynomials in
one variable over a field lack division, and some types might not even
have subtraction defined. Nevertheless, many BLAS operations would make
sense for all of these types.</p>
<p>“Constraining matrix and vector element types and scalars” means
defining how these types must behave in order for our algorithms to make
sense. This includes both syntactic and semantic constraints. We have
three goals:</p>
<ol type="1">
<li><p>to help implementers implement our algorithms correctly;</p></li>
<li><p>to give implementers the freedom to make quality of
implementation (QoI) enhancements, for both performance and accuracy;
and</p></li>
<li><p>to help users understand what types they may use with our
algorithms.</p></li>
</ol>
<p>The whole point of the BLAS was to identify key operations for
vendors to optimize. Thus, performance is a major concern. “Accuracy”
here refers to either to rounding error or to approximation error (for
matrix or vector element types where either makes sense).</p>
<h3 data-number="11.7.2" id="value-type-constraints-do-not-suffice-to-describe-algorithm-behavior"><span class="header-section-number">11.7.2</span> Value type constraints do
not suffice to describe algorithm behavior<a href="#value-type-constraints-do-not-suffice-to-describe-algorithm-behavior" class="self-link"></a></h3>
<p>LEWG’s 2020 review of P1673R2 asked us to investigate
conceptification of its algorithms. “Conceptification” here refers to an
effort like that of P1813R0 (“A Concept Design for the Numeric
Algorithms”), to come up with concepts that could be used to constrain
the template parameters of numeric algorithms like <code>reduce</code>
or <code>transform</code>. (We are not referring to LEWGI’s request for
us to consider generalizing our algorithm’s parameters from
<code>mdspan</code> to a hypothetical multidimensional array concept. We
discuss that above, in the “Why use <code>mdspan</code>?” section.) The
numeric algorithms are relevant to P1673 because many of the algorithms
proposed in P1673 look like generalizations of <code>reduce</code> or
<code>transform</code>. We intend for our algorithms to be generic on
their matrix and vector element types, so these questions matter a lot
to us.</p>
<p>We agree that it is useful to set constraints that make it possible
to reason about correctness of algorithms. However, we do not think
constraints on value types suffice for this purpose. First, requirements
like associativity are too strict to be useful for practical types.
Second, what we really want to do is describe the behavior of
algorithms, regardless of value types’ semantics. “The algorithm may
reorder sums” means something different than “addition on the terms in
the sum is associative.”</p>
<h3 data-number="11.7.3" id="associativity-is-too-strict"><span class="header-section-number">11.7.3</span> Associativity is too
strict<a href="#associativity-is-too-strict" class="self-link"></a></h3>
<p>P1813R0 requires associative addition for many algorithms, such as
<code>reduce</code>. However, many practical arithmetic systems that
users might like to use with algorithms like <code>reduce</code> have
non-associative addition. These include</p>
<ul>
<li><p>systems with rounding;</p></li>
<li><p>systems with an “infinity”: e.g., if 10 is Inf, 3 + 8 - 7 could
be either Inf or 4; and</p></li>
<li><p>saturating arithmetic: e.g., if 10 saturates, 3 + 8 - 7 could be
either 3 or 4.</p></li>
</ul>
<p>Note that the latter two arithmetic systems have nothing to do with
rounding error. With saturating integer arithmetic, parenthesizing a sum
in different ways might give results that differ by as much as the
saturation threshold. It’s true that many non-associative arithmetic
systems behave “associatively enough” that users don’t fear
parallelizing sums. However, a concept with an exact property (like
“commutative semigroup”) isn’t the right match for “close enough,” just
like <code>operator==</code> isn’t the right match for describing
“nearly the same.” For some number systems, a rounding error bound might
be more appropriate, or guarantees on when underflow or overflow may
occur (as in POSIX’s <code>hypot</code>).</p>
<p>The problem is a mismatch between the requirement we want to express
– that “the algorithm may reparenthesize addition” – and the constraint
that “addition is associative.” The former describes the algorithm’s
behavior, while the latter describes the types used with that algorithm.
Given the huge variety of possible arithmetic systems, an approach like
the Standard’s use of <em>GENERALIZED_SUM</em> to describe
<code>reduce</code> and its kin seems more helpful. If the Standard
describes an algorithm in terms of <em>GENERALIZED_SUM</em>, then that
tells the caller what the algorithm might do. The caller then takes
responsibility for interpreting the algorithm’s results.</p>
<p>We think this is important both for adding new algorithms (like those
in this proposal) and for defining behavior of an algorithm with respect
to different <code>ExecutionPolicy</code> arguments. (For instance,
<code>execution::par_unseq</code> could imply that the algorithm might
change the order of terms in a sum, while <code>execution::par</code>
need not. Compare to <code>MPI_Op_create</code>’s <code>commute</code>
parameter, that affects the behavior of algorithms like
<code>MPI_Reduce</code> when used with the resulting user-defined
reduction operator.)</p>
<h3 data-number="11.7.4" id="generalizing-associativity-helps-little"><span class="header-section-number">11.7.4</span> Generalizing associativity
helps little<a href="#generalizing-associativity-helps-little" class="self-link"></a></h3>
<p>Suppose we accept that associativity and related properties are not
useful for describing our proposed algorithms. Could there be a
generalization of associativity that <em>would</em> be useful? P1813R0’s
most general concept is a <code>magma</code>. Mathematically, a
<em>magma</em> is a set M with a binary operation ×, such that if a and
b are in M, then a × b is in M. The operation need not be associative or
commutative. While this seems almost too general to be useful, there are
two reasons why even a magma is too specific for our proposal.</p>
<ol type="1">
<li><p>A magma only assumes one set, that is, one type. This does not
accurately describe what the algorithms do, and it excludes useful
features like mixed precision and types that use expression
templates.</p></li>
<li><p>A magma is too specific, because algorithms are useful even if
the binary operation is not closed.</p></li>
</ol>
<p>First, even for simple linear algebra operations that “only” use plus
and times, there is no one “set M” over which plus and times operate.
There are actually three operations: plus, times, and assignment. Each
operation may have completely heterogeneous input(s) and output. The
sets (types) that may occur vary from algorithm to algorithm, depending
on the input type(s), and the algebraic expression(s) that the algorithm
is allowed to use. We might need several different concepts to cover all
the expressions that algorithms use, and the concepts would end up being
less useful to users than the expressions themselves.</p>
<p>For instance, consider the Level 1 BLAS “AXPY” function. This
computes <code>y[i] = alpha * x[i] + y[i]</code> elementwise. What type
does the expression <code>alpha * x[i] + y[i]</code> have? It doesn’t
need to have the same type as <code>y[i]</code>; it just needs to be
assignable to <code>y[i]</code>. The types of <code>alpha</code>,
<code>x[i]</code>, and <code>y[i]</code> could all differ. As a simple
example, <code>alpha</code> might be <code>int</code>, <code>x[i]</code>
might be <code>float</code>, and <code>y[i]</code> might be
<code>double</code>. The types of <code>x[i]</code> and
<code>y[i]</code> might be more complicated; e.g., <code>x[i]</code>
might be a polynomial with <code>double</code> coefficients, and
<code>y[i]</code> a polynomial with <code>float</code> coefficients. If
those polynomials use expression templates, then slightly different sum
expressions involving <code>x[i]</code> and/or <code>y[i]</code> (e.g.,
<code>alpha * x[i] + y[i]</code>, <code>x[i] + y[i]</code>, or
<code>y[i] + x[i]</code>) might all have different types, all of which
differ from value type of <code>x</code> or <code>y</code>. All of these
types must be assignable and convertible to the output value type.</p>
<p>We could try to describe this with a concept that expresses a sum
type. The sum type would include all the types that might show up in the
expression. However, we do not think this would improve clarity over
just the expression itself. Furthermore, different algorithms may need
different expressions, so we would need multiple concepts, one for each
expression. Why not just use the expressions to describe what the
algorithms can do?</p>
<p>Second, the magma concept is not helpful even if we only had one set
M, because our algorithms would still be useful even if binary
operations were not closed over that set. For example, consider a
hypothetical user-defined rational number type, where plus and times
throw if representing the result of the operation would take more than a
given fixed amount of memory. Programmers might handle this exception by
falling back to different algorithms. Neither plus or times on this type
would satisfy the magma requirement, but the algorithms would still be
useful for such a type. One could consider the magma requirement
satisfied in a purely syntactic sense, because of the return type of
plus and times. However, saying that would not accurately express the
type’s behavior.</p>
<p>This point returns us to the concerns we expressed earlier about
assuming associativity. “Approximately associative” or “usually
associative” are not useful concepts without further refinement. The way
to refine these concepts usefully is to describe the behavior of a type
fully, e.g., the way that IEEE 754 describes the behavior of
floating-point numbers. However, algorithms rarely depend on all the
properties in a specification like IEEE 754. The problem, again, is that
we need to describe what algorithms do – e.g., that they can rearrange
terms in a sum – not how the types that go into the algorithms
behave.</p>
<p>In summary:</p>
<ul>
<li><p>Many useful types have nonassociative or even non-closed
arithmetic.</p></li>
<li><p>Lack of (e.g.,) associativity is not just a rounding error
issue.</p></li>
<li><p>It can be useful to let algorithms do things like reparenthesize
sums or products, even for types that are not associative.</p></li>
<li><p>Permission for an algorithm to reparenthesize sums is not the
same as a concept constraining the terms in the sum.</p></li>
<li><p>We can and do use existing Standard language, like
<em>GENERALIZED_SUM</em>, for expressing permissions that algorithms
have.</p></li>
</ul>
<p>In the sections that follow, we will describe a different way to
constrain the matrix and vector element types and scalars in our
algorithms. We will start by categorizing the different quality of
implementation (QoI) enhancements that implementers might like to make.
These enhancements call for changing algorithms in different ways. We
will distinguish textbook from non-textbook ways of changing algorithms,
explain that we only permit non-textbook changes for floating-point
types, then develop constraints on types that permit textbook
changes.</p>
<h3 data-number="11.7.5" id="categories-of-qoi-enhancements"><span class="header-section-number">11.7.5</span> Categories of QoI
enhancements<a href="#categories-of-qoi-enhancements" class="self-link"></a></h3>
<p>An important goal of constraining our algorithms is to give
implementers the freedom to make QoI enhancements. We categorize QoI
enhancements in three ways:</p>
<ol type="1">
<li><p>those that depend entirely on the computer architecture;</p></li>
<li><p>those that might have architecture-dependent parameters, but
could otherwise be written in an architecture-independent way;
and</p></li>
<li><p>those that diverge from a textbook description of the algorithm,
and depend on element types having properties more specific than what
that description requires.</p></li>
</ol>
<p>An example of Category (1) would be special hardware instructions
that perform matrix-matrix multiplications on small, fixed-size blocks.
The hardware might only support a few types, such as integers,
fixed-point reals, or floating-point types. Implementations might use
these instructions for the entire algorithm, if the problem sizes and
element types match the instruction’s requirements. They might also use
these instructions to solve subproblems. In either case, these
instructions might reorder sums or create temporary values.</p>
<p>Examples of Category (2) include blocking to increase cache or
translation lookaside buffer (TLB) reuse, or using SIMD instructions
(given the Parallelism TS’ inclusion of SIMD). Many of these
optimizations relate to memory locality or parallelism. For an overview,
see (Goto 2008) or Section 2.6 of (Demmel 1997). All such optimizations
reorder sums and create temporary values.</p>
<p>Examples of Category (3) include Strassen’s algorithm for matrix
multiplication. The textbook formulation of matrix multiplication only
uses additions and multiplies, but Strassen’s algorithm also performs
subtractions. A common feature of Category (3) enhancements is that
their implementation diverges from a “textbook description of the
algorithm” in ways beyond just reordering sums. As a “textbook,” we
recommend either (Strang 2016), or the concise mathematical description
of operations in the BLAS Standard. In the next section, we will list
properties of textbook descriptions, and explain some ways in which QoI
enhancements might fail to adhere to those properties.</p>
<h3 data-number="11.7.6" id="properties-of-textbook-algorithm-descriptions"><span class="header-section-number">11.7.6</span> Properties of textbook
algorithm descriptions<a href="#properties-of-textbook-algorithm-descriptions" class="self-link"></a></h3>
<p>“Textbook descriptions” of the algorithms we propose tend to have the
following properties. For each property, we give an example of a
“non-textbook” algorithm, and how it assumes something extra about the
matrix’s element type.</p>
<ol type="a">
<li><p>They compute floating-point sums straightforwardly (possibly
reordered, or with temporary intermediate values), rather than using any
of several algorithms that improve accuracy (e.g., compensated
summation) or even make the result independent of evaluation order (see
Demmel 2013). All such non-straightforward algorithms depend on
properties of floating-point arithmetic. We will define below what
“possibly reordered, or with temporary intermediate values”
means.</p></li>
<li><p>They use only those arithmetic operations on the matrix and
vector element types that the textbook description of the algorithm
requires, even if using other kinds of arithmetic operations would
improve performance or give an asymptotically faster algorithm.</p></li>
<li><p>They use exact algorithms (not considering rounding error),
rather than approximations (that would not be exact even if computing
with real numbers).</p></li>
<li><p>They do not use parallel algorithms that would give an
asymptotically faster parallelization in the theoretical limit of
infinitely many available parallel processing units, at the cost of
likely unacceptable rounding error in floating-point
arithmetic.</p></li>
</ol>
<p>As an example of (b), the textbook matrix multiplication algorithm
only adds or multiplies the matrices’ elements. In contrast, Strassen’s
algorithm for matrix-matrix multiply subtracts as well as adds and
multiplies the matrices’ elements. Use of subtraction assumes that
arbitrary elements have an additive inverse, but the textbook matrix
multiplication algorithm makes sense even for element types that lack
additive inverses for all elements. Also, use of subtractions changes
floating-point rounding behavior in a way that was only fully understood
recently (see Demmel 2007).</p>
<p>As an example of (c), the textbook substitution algorithm for solving
triangular linear systems is exact. In contrast, one can approximate
triangular solve with a stationary iteration. (See, e.g., Section 5 of
(Chow 2015). That paper concerns the sparse matrix case; we cite it
merely as an example of an approximate algorithm, not as a
recommendation for dense triangular solve.) Approximation only makes
sense for element types that have enough precision for the approximation
to be accurate. If the approximation checks convergence, than the
algorithm also requires less-than comparison of absolute values of
differences.</p>
<p>Multiplication by the reciprocal of a number, rather than division by
that number, could fit into (b) or (c). As an example of (c),
implementations for hardware where floating-point division is slow
compared with multiplication could use an approximate reciprocal
multiplication to implement division.</p>
<p>As an example of (d), the textbook substitution algorithm for solving
triangular linear systems has data dependencies that limit its
theoretical parallelism. In contrast, one can solve a triangular linear
system by building all powers of the matrix in parallel, then solving
the linear system as with a Krylov subspace method. This approach is
exact for real numbers, but commits too much rounding error to be useful
in practice for all but the smallest linear systems. In fact, the
algorithm requires that the matrix’s element type have precision
exponential in the matrix’s dimension.</p>
<p>Many of these non-textbook algorithms rely on properties of
floating-point arithmetic. Strassen’s algorithm makes sense for unsigned
integer types, but it could lead to unwarranted and unexpected overflow
for signed integer types. Thus, we think it best to limit implementers
to textbook algorithms, unless all matrix and vector element types are
floating-point types. We always forbid non-textbook algorithms of type
(d). If all matrix and vector element types are floating-point types, we
permit non-textbook algorithms of Types (a), (b), and (c), under two
conditions:</p>
<ol type="1">
<li><p>they satisfy the complexity requirements; and</p></li>
<li><p>they result in a <em>logarithmically stable</em> algorithm, in
the sense of (Demmel 2007).</p></li>
</ol>
<p>We believe that Condition (2) is a reasonable interpretation of
Section 2.7 of the BLAS Standard. This says that “no particular
computational order is mandated by the function specifications. In other
words, any algorithm that produces results ‘close enough’ to the usual
algorithms presented in a standard book on matrix computations is
acceptable.” Examples of what the BLAS Standard considers “acceptable”
include Strassen’s algorithm, and implementing matrix multiplication as
<code>C = (alpha * A) * B + (beta * C)</code>,
<code>C = alpha * (A * B) + (beta * C)</code>, or
<code>C = A * (alpha * B) + (beta * C)</code>.</p>
<p>“Textbook algorithms” includes optimizations commonly found in BLAS
implementations. This includes any available hardware acceleration, as
well as the locality and parallelism optimizations we describe below.
Thus, we think restricting generic implementations to textbook
algorithms will not overly limit implementers.</p>
<p>The set of floating-point types currently has three members:
<code>float</code>, <code>double</code>, and <code>long double</code>.
If a proposal like P1467R4 (“Extended floating-point types and standard
names”) is accepted, it will grow to include implementation-specific
types, such as short or extended-precision floats. This “future-proofs”
our proposal in some sense, though implementers will need to take care
to avoid approximations if the element type lacks the needed
precision.</p>
<h3 data-number="11.7.7" id="reordering-sums-and-creating-temporaries"><span class="header-section-number">11.7.7</span> Reordering sums and creating
temporaries<a href="#reordering-sums-and-creating-temporaries" class="self-link"></a></h3>
<p>Even textbook descriptions of linear algebra algorithms presume the
freedom to reorder sums and create temporary values. Optimizations for
memory locality and parallelism depend on this. This freedom imposes
requirements on algorithms’ matrix and vector element types.</p>
<p>We could get this freedom either by limiting our proposal to the
Standard’s current arithmetic types, or by forbidding reordering and
temporaries for types other than arithmetic types. However, doing so
would unnecessarily prevent straightforward optimizations for small and
fast types that act just like arithmetic types. This includes so-called
“short floats” such as bfloat16 or binary16, extended-precision
floating-point numbers, and fixed-point reals. Some of these types may
be implementation defined, and others may be user-specified. We intend
to permit implementers to optimize for these types as well. This
motivates us to describe our algorithms’ type requirements in a generic
way.</p>
<h4 data-number="11.7.7.1" id="special-case-only-one-element-type"><span class="header-section-number">11.7.7.1</span> Special case: Only one
element type<a href="#special-case-only-one-element-type" class="self-link"></a></h4>
<p>We find it easier to think about type requirements by starting with
the assumption that all element and scalar types in algorithms are the
same. One can then generalize to input element type(s) that might differ
from the output element type and/or scalar result type.</p>
<p>Optimizations for memory locality and parallelism both create
temporary values, and change the order of sums. For example,
reorganizing matrix data to reduce stride involves making a temporary
copy of a subset of the matrix, and accumulating partial sums into the
temporary copy. Thus, both kinds of optimizations impose a common set of
requirements and assumptions on types. Let <code>value_type</code> be
the output <code>mdspan</code>’s <code>value_type</code>.
Implementations may:</p>
<ol type="1">
<li><p>create arbitrarily many objects of type <code>value_type</code>,
value-initializing them or direct-initializing them with any existing
object of that type;</p></li>
<li><p>perform sums in any order; or</p></li>
<li><p>replace any value with the sum of that value and a
value-initialized <code>value_type</code> object.</p></li>
</ol>
<p>Assumption (1) implies that the output value type is
<code>semiregular</code>. Contrast with
<strong>[algorithms.parallel.exec]</strong>: “Unless otherwise stated,
implementations may make arbitrary copies of elements of type
<code>T</code>, from sequences where
<code>is_trivially_copy_constructible_v&lt;T&gt;</code> and
<code>is_trivially_destructible_v&lt;T&gt;</code> are true.” We omit the
trivially constructible and destructible requirements here and permit
any <code>semiregular</code> type. Linear algebra algorithms assume
mathematical properties that let us impose more specific requirements
than general parallel algorithms. Nevertheless, implementations may want
to enable optimizations that create significant temporary storage only
if the value type is trivially constructible, trivially destructible,
and not too large.</p>
<p>Regarding Assumption (2): The freedom to compute sums in any order is
not necessarily a type constraint. Rather, it’s a right that the
algorithm claims, regardless of whether the type’s addition is
associative or commutative. For example, floating-point sums are not
associative, yet both parallelization and customary linear algebra
optimizations rely on reordering sums. See the above “Value type
constraints do not suffice to describe algorithm behavior” section for a
more detailed explanation.</p>
<p>Regarding Assumption (3), we do not actually say that
value-initialization produces a two-sided additive identity. What
matters is what the algorithm’s implementation may do, not whether the
type actually behaves in this way.</p>
<h4 data-number="11.7.7.2" id="general-case-multiple-input-element-types"><span class="header-section-number">11.7.7.2</span> General case: Multiple
input element types<a href="#general-case-multiple-input-element-types" class="self-link"></a></h4>
<p>An important feature of P1673 is the ability to compute with mixed
matrix or vector element types. For instance,
<code>add(y, scaled(alpha, x), z)</code> implements the operation z = y
+ alpha*x, an elementwise scaled vector sum. The element types of the
vectors x, y, and z could be all different, and could differ from the
type of alpha.</p>
<h5 data-number="11.7.7.2.1" id="accumulate-into-output-value-type"><span class="header-section-number">11.7.7.2.1</span> Accumulate into output
value type<a href="#accumulate-into-output-value-type" class="self-link"></a></h5>
<p>Generic algorithms would use the output <code>mdspan</code>’s
<code>value_type</code> to accumulate partial sums, and for any
temporary results. This is the analog of <code>std::reduce</code>’s
scalar result type <code>T</code>. Implementations for floating-point
types might accumulate into higher-precision temporaries, or use other
ways to increase accuracy when accumulating partial sums, but the output
<code>mdspan</code>’s <code>value_type</code> would still control
accumulation behavior in general.</p>
<h5 data-number="11.7.7.2.2" id="proxy-references-or-expression-templates"><span class="header-section-number">11.7.7.2.2</span> Proxy references or
expression templates<a href="#proxy-references-or-expression-templates" class="self-link"></a></h5>
<ol type="1">
<li><p>Proxy references: The input and/or output <code>mdspan</code>
might have an accessor with a <code>reference</code> type other than
<code>element_type&amp;</code>. For example, the output
<code>mdspan</code> might have a value type <code>value_type</code>, but
its <code>reference</code> type might be
<code>atomic_ref&lt;value_type&gt;</code>.</p></li>
<li><p>Expression templates: The element types themselves might have
arithmetic operations that defer the actual computation until the
expression is assigned. These “expression template” types typically hold
some kind of reference or pointer to their input arguments.</p></li>
</ol>
<p>Neither proxy references nor expression template types are
<code>semiregular</code>, because they behave like references, not like
values. However, we can still require that their underlying value type
be <code>semiregular</code>. For instance, the possiblity of proxy
references just means that we need to use the output
<code>mdspan</code>‘s <code>value_type</code> when constructing or
value-initializing temporary values, rather than trying to deduce the
value type from the type of an expression that indexes into the output
<code>mdspan</code>. Expression templates just mean that we need to use
the output <code>mdspan</code>’s <code>value_type</code> to construct or
value-initialize temporaries, rather than trying to deduce the
temporaries’ type from the right-hand side of the expression.</p>
<p>The <code>z = y + alpha*x</code> example above shows that some of the
algorithms we propose have multiple terms in a sum on the right-hand
side of the expression that defines the algorithm. If algorithms have
permission to rearrange the order of sums, then they need to be able to
break up such expressions into separate terms, even if some of those
expressions are expression templates.</p>
<h3 data-number="11.7.8" id="textbook-algorithm-description-in-semiring-terms"><span class="header-section-number">11.7.8</span> “Textbook” algorithm
description in semiring terms<a href="#textbook-algorithm-description-in-semiring-terms" class="self-link"></a></h3>
<p>As we explain in the “Value type constraints do not suffice to
describe algorithm behavior” section above, we deliberately constrain
matrix and vector element types to require associative addition. This
means that we do not, for instance, define concepts like “ring” or
“group.” We cannot even speak of a single set of values that would
permit defining things like a “ring” or “group.” This is because our
algorithms must handle mixed value types, expression templates, and
proxy references. However, it may still be helpful to use mathematical
language to explain what we mean by “a textbook description of the
algorithm.”</p>
<p>Most of the algorithms we propose only depend on addition and
multiplication. We describe these algorithms as if working on elements
of a <em>semiring</em> with possibly noncommutative multiplication. The
only difference between a semiring and a ring is that a semiring does
not require all elements to have an additive inverse. That is, addition
is allowed, but not subtraction. Implementers may apply any mathematical
transformation to the expressions that would give the same result for
any semiring.</p>
<h4 data-number="11.7.8.1" id="why-a-semiring"><span class="header-section-number">11.7.8.1</span> Why a semiring?<a href="#why-a-semiring" class="self-link"></a></h4>
<p>We use a semiring because</p>
<ol type="1">
<li><p>we generally want to reorder terms in sums, but we do not want to
order terms in products; and</p></li>
<li><p>we do not want to assume that subtraction works.</p></li>
</ol>
<p>The first is because linear algebra computations are useful for
matrix or vector element types with noncommutative multiplication, such
as quaternions or matrices. The second is because algebra operations
might be useful for signed integers, where a formulation using
subtraction risks unexpected undefined behavior.</p>
<h4 data-number="11.7.8.2" id="semirings-and-testing"><span class="header-section-number">11.7.8.2</span> Semirings and testing<a href="#semirings-and-testing" class="self-link"></a></h4>
<p>It’s important that implementers be able to test our proposed
algorithms for custom element types, not just the built-in arithmetic
types. We don’t want to require hypothetical “exact real arithmetic”
types that take particular expertise to implement. Instead, we propose
testing with simple classes built out of unsigned integers. This section
is not part of our Standard Library proposal, but we include it to give
guidance to implementers and to show that it’s feasible to test our
proposal.</p>
<h4 data-number="11.7.8.3" id="commutative-multiplication"><span class="header-section-number">11.7.8.3</span> Commutative
multiplication<a href="#commutative-multiplication" class="self-link"></a></h4>
<p>C++ unsigned integers implement commutative rings. (Rings always have
commutative addition; a “commutative ring” has commutative
multiplication as well.) We may transform (say) <code>uint32_t</code>
into a commutative semiring by wrapping it in a class that does not
provide unary or binary <code>operator-</code>. Adding a “tag” template
parameter to this class would let implementers build tests for mixed
element types.</p>
<h4 data-number="11.7.8.4" id="noncommutative-multiplication"><span class="header-section-number">11.7.8.4</span> Noncommutative
multiplication<a href="#noncommutative-multiplication" class="self-link"></a></h4>
<p>The semiring of 2x2 matrices with element type a commutative semiring
is itself a semiring, but with noncommutative multiplication. This is a
good way to build a noncommutative semiring for testing.</p>
<h3 data-number="11.7.9" id="summary-1"><span class="header-section-number">11.7.9</span> Summary<a href="#summary-1" class="self-link"></a></h3>
<ul>
<li><p>Constraining the matrix and vector element types and scalar types
in our functions gives implementers the freedom to make QoI enhancements
without risking correctness.</p></li>
<li><p>We think describing algorithms’ behavior and implementation
freedom is more useful than mathematical concepts like “ring.” For
example, we permit implementations to reorder sums, but this does not
mean that they assume sums are associative. This is why we do not define
a hierarchy of number concepts.</p></li>
<li><p>We categorize different ways that implementers might like to
change algorithms, list categories we exclude and categories we permit,
and use the permitted categories to derive constraints on the types of
matrix and vector elements and scalar results.</p></li>
<li><p>We explain how a semiring is a good way to talk about
implementation freedom, even though we do not think it is a good way to
constrain types. We then use the semiring description to explain how
implementers can test generic algorithms.</p></li>
</ul>
<h2 data-number="11.8" id="support-for-user-defined-complex-number-types"><span class="header-section-number">11.8</span> Support for user-defined
complex number types<a href="#support-for-user-defined-complex-number-types" class="self-link"></a></h2>
<h3 data-number="11.8.1" id="conj-does-not-have-the-desired-interface"><span class="header-section-number">11.8.1</span> <code>conj</code> does not
have the desired interface<a href="#conj-does-not-have-the-desired-interface" class="self-link"></a></h3>
<p>Based on precedence from the BLAS and LAPACK, generic linear algebra
code that works for both complex and real numbers uses the “conjugate
transpose” for both cases, and intends conjugation to be the identity
for real numbers. P1673 users may thus want to apply
<code>conjugate_transposed</code> to matrices of arbitrary value
types.</p>
<p>The Standard currently offers <code>conj</code> as the way to compute
the conjugate of a number. However, there are two issues with
<code>conj</code>.</p>
<ol type="1">
<li><p>For arguments of arithmetic type, <code>conj</code> returns
<code>complex</code>. The resulting value type change is mathematically
unexpected, and it can hinder use of an optimized BLAS.</p></li>
<li><p>P1673 users have good reasons to define their own complex number
types, but users cannot overload <code>conj</code> for these
types.</p></li>
</ol>
<h3 data-number="11.8.2" id="why-users-define-their-own-complex-number-types"><span class="header-section-number">11.8.2</span> Why users define their own
complex number types<a href="#why-users-define-their-own-complex-number-types" class="self-link"></a></h3>
<ol type="1">
<li><p><code>complex&lt;R&gt;</code> only permits <code>R</code> =
<code>float</code>, <code>double</code>, and
<code>long double</code>.</p></li>
<li><p><code>complex&lt;R&gt;</code> only has <code>sizeof(R)</code>
alignment, not <code>2 * sizeof(R)</code>.</p></li>
<li><p>Some C++ extensions cannot use <code>complex&lt;R&gt;</code>,
because they require annotations on a type’s member functions.</p></li>
</ol>
<p>Users define their own complex number types for three reasons. First,
the C++ Standard currently supports <code>complex&lt;R&gt;</code> only
for <code>R</code> = <code>float</code>, <code>double</code>, and
<code>long double</code>. This prevents use of other types,
including</p>
<ul>
<li><p>signed integers (the resulting complex numbers represent the
<em>Gaussian integers</em>);</p></li>
<li><p>“short” low-precision floating-point or fixed-point number types
that are critical for performance of machine learning
applications;</p></li>
<li><p>extended-precision floating-point types like binary128 that can
improve the accuracy of floating-point sums, reduce parallel
nondeterminism, and make sums less dependent on evaluation order;
and</p></li>
<li><p>custom number types such as “bigfloats” (custom
arbitrary-precision floating-point types).</p></li>
</ul>
<p>Second, the Standard explicitly specifies that
<code>complex&lt;R&gt;</code> has the same alignment as
<code>R[2]</code>. That is, it is aligned to <code>sizeof(R)</code>.
Some systems would give better parallel or vectorized performance if
complex numbers were aligned to <code>2 * sizeof(R)</code>. Some C++
extensions define their own complex number types partly for this reason.
Software libraries that use these custom complex number types tempt
users to alias between <code>complex&lt;R&gt;</code> and these custom
types, which would have the same bit representation except for
alignment. This has led to crashes or worse in software projects that
the authors have worked on. Third, some C++ extensions cannot use
<code>complex</code>, because they require types’ member functions to
have special annotations, in order to compile code to make use of
accelerator hardware.</p>
<p>These issues have led several software libraries and C++ extensions
to define their own complex number types. These include CUDA, Kokkos,
and Thrust. The SYCL standard is contemplating adding a custom complex
number type. One of the authors wrote <code>Kokkos::complex</code> circa
2014 to make it possible to build and run Trilinos’ linear solvers with
complex numbers on NVIDIA graphics processing units (GPUs).</p>
<h3 data-number="11.8.3" id="why-users-want-to-conjugate-matrices-of-real-numbers"><span class="header-section-number">11.8.3</span> Why users want to
“conjugate” matrices of real numbers<a href="#why-users-want-to-conjugate-matrices-of-real-numbers" class="self-link"></a></h3>
<p>It’s possible to describe many linear algebra algorithms in a way
that works for both complex and real numbers, by treating conjugation as
the identity for real numbers. This makes the “conjugate transpose” just
the transpose for a matrix of real numbers. Matlab takes this approach,
by defining the single quote operator to take the conjugate transpose if
its argument is complex, and the transpose if its argument is real. The
Fortran BLAS also supports this, by letting users specify the
<code>&#39;Conjugate Transpose&#39;</code> (<code>TRANSA=&#39;C&#39;</code>) even for
real routines like <code>DGEMM</code> (double-precision general
matrix-matrix multiply). Krylov subspace methods in Trilinos’ Anasazi
and Belos packages also follow a Matlab-like generic approach.</p>
<p>Even though we think it should be possible to write “generic” (real
or complex) linear algebra code using <code>conjugate_transposed</code>,
we still need to distinguish between symmetric and Hermitian matrix
algorithms. This is because symmetric does <em>not</em> mean the same
thing as Hermitian for matrices of complex numbers. For example, a
matrix whose off-diagonal elements are all <code>3 + 4i</code> is
symmetric, but not Hermitian. Complex symmetric matrices are useful in
practice, for example when modeling damped vibrations (Craven 1969).</p>
<h3 data-number="11.8.4" id="effects-of-conjs-real-to-complex-change"><span class="header-section-number">11.8.4</span> Effects of
<code>conj</code>’s real-to-complex change<a href="#effects-of-conjs-real-to-complex-change" class="self-link"></a></h3>
<p>The fact that <code>conj</code> for arithmetic-type arguments returns
<code>complex</code> may complicate or prevent implementers from using
an existing optimized BLAS library. If the user calls
<code>matrix_product</code> with matrices all of value type
<code>double</code>, use of the (mathematically harmless)
<code>conjugate_transposed</code> function would make one matrix have
value type <code>complex&lt;double&gt;</code>. Implementations could
undo this value type change for known layouts and accessors, but would
need to revert to generic code otherwise.</p>
<p>For example, suppose that a custom real value type
<code>MyReal</code> has arithmetic operators defined to permit all
needed mixed-type expressions with <code>double</code>, where
<code>double</code> times <code>MyReal</code> and <code>MyReal</code>
times <code>double</code> both “promote” to <code>MyReal</code>. Users
may then call <code>matrix_product(A, B, C)</code> with <code>A</code>
having value type <code>double</code>, <code>B</code> having value type
<code>MyReal</code>, and <code>C</code> having a value type
<code>MyReal</code>. However,
<code>matrix_product(conjugate_transposed(A), B, C)</code> would not
compile, due to
<code>complex&lt;decltype(declval&lt;double&gt;() * declval&lt;MyReal&gt;())&gt;</code>
not being well formed.</p>
<h3 data-number="11.8.5" id="lewg-feedback-on-r8-solution"><span class="header-section-number">11.8.5</span> LEWG feedback on R8
solution<a href="#lewg-feedback-on-r8-solution" class="self-link"></a></h3>
<p>In R8 of this paper, we proposed an exposition-only function
<em><code>conj-if-needed</code></em>. For arithmetic types, it would be
the identity function. This would fix Issue (1). For all other types, it
would call <code>conj</code> through argument-dependent lookup (ADL),
just like how <code>iter_swap</code> calls <code>swap</code>. This would
fix Issue (2). However, it would force users who define custom
<em>real</em> number types to define a trivial <code>conj</code> (in
their own namespace) for their type. The alternative would be to make
<em><code>conj-if-needed</code></em> the identity if it could not find
<code>conj</code> via ADL lookup. However, that would cause silently
incorrect results for users who define a custom complex number type, but
forget or misspell <code>conj</code>.</p>
<p>When reviewing R8, LEWG expressed a preference for a different
solution.</p>
<ol type="1">
<li><p>Temporarily change P1673 to permit use of <code>conjugated</code>
and <code>conjugate_transposed</code> only for value types that are
either <code>complex</code> or arithmetic types. Add a Note that reminds
readers to look out for Steps (2) and (3) below.</p></li>
<li><p>Write a separate paper which introduces a user-visible
customization point, provisionally named <code>conjugate</code>. The
paper could use any of various proposed library-only customization point
mechanisms, such as the customization point objects used by ranges or
<code>tag_invoke</code> (see
<a href="https://wg21.link/p1895r0">P1895R0</a>, with the expectation
that LEWG and perhaps also EWG (see e.g.,
<a href="https://wg21.link/P2547">P2547</a>) may express a preference
for a different mechanism.</p></li>
<li><p>If LEWG accepts the <code>conjugate</code> customization point,
then change P1673 again to use <code>conjugate</code> (thus replacing
R8’s <em><code>conj-if-needed</code></em>). This would thus reintroduce
support for custom complex numbers.</p></li>
</ol>
<h3 data-number="11.8.6" id="sg6s-response-to-lewgs-r8-feedback"><span class="header-section-number">11.8.6</span> SG6’s response to LEWG’s R8
feedback<a href="#sg6s-response-to-lewgs-r8-feedback" class="self-link"></a></h3>
<p>SG6 small group (there was no quorum) reviewed P1673 on 2022/06/09,
after LEWG’s R8 review on 2022/05/24. SG6 small group expressed the
following:</p>
<ul>
<li><p>Being able to write <code>conjugated(A)</code> or
<code>conjugate_transposed(A)</code> for a matrix or vector
<code>A</code> of user-defined types is reasonably integral to the
proposal. We generically oppose deferring it based on the hope that
we’ll be able to specify it in a nicer way in the future, with some new
customization point syntax.</p></li>
<li><p>A simple, teachable rule: Do ADL-ONLY lookup (preventing finding
<code>std::conj</code> for primitive types) for <code>conj</code> (as
with ranges); if you find something you use it, and if you don’t, you do
nothing (conjugation is the identity). (“Primitives aren’t that
special.”) Benefit is that custom real types work out of the
box.</p></li>
<li><p>The alternative: specify that if users choose to use
<code>conjugated</code> or <code>conjugate_transposed</code> with a
user-defined type, then they MUST supply the <code>conj</code>
ADL-findable thing, else ill-formed. This is a safety mechanism that may
not have been considered previously by LEWG. (Make primitives special,
to regain safety. The cost is that custom real types need to have a
<code>conj</code> ADL-findable, if users use <code>conjugated</code> or
<code>conjugate_transposed</code>.)</p></li>
</ul>
<h3 data-number="11.8.7" id="current-solution"><span class="header-section-number">11.8.7</span> Current solution<a href="#current-solution" class="self-link"></a></h3>
<p>We have adopted SG6 small group’s recommendation, with a slight
wording modification to make it obvious that the conjugate of an
arithmetic type returns the same type as its input.</p>
<p>We propose an exposition-only function object
<em><code>conj-if-needed</code></em>. For arithmetic types, it would
behave as the identity function. If it can call <code>conj</code>
through ADL-only (unqualified) lookup, it does so. Otherwise, it again
would behave as the identity function.</p>
<p>This approach has the following advantages.</p>
<ol type="1">
<li><p>Most custom number types, noncomplex or complex, will work “out
of the box.” Custom complex number types would likely already have an
ADL-findable <code>conj</code> defined, for interface compatibility with
<code>std::complex</code>.</p></li>
<li><p>Conjugation will preserve the type of its argument.</p></li>
<li><p>It uses existing C++ idioms and interfaces for complex
numbers.</p></li>
<li><p>It does not depend on a future customization point syntax or
library convention.</p></li>
</ol>
<h2 data-number="11.9" id="support-for-division-with-noncommutative-multiplication"><span class="header-section-number">11.9</span> Support for division with
noncommutative multiplication<a href="#support-for-division-with-noncommutative-multiplication" class="self-link"></a></h2>
<p>An important feature of this proposal is its support for value types
that have noncommutative multiplication. Examples include square
matrices with a fixed number of rows and columns, and quaternions and
their generalizations. Most of the algorithms in this proposal only add
or multiply arbitrary value types, so preserving the order of
multiplication arguments is straightforward. The various triangular
solve algorithms are an exception, because they need to perform
divisions as well.</p>
<p>If multiplication commutes and if a type has division, then the
division x ÷ y is just x times (the multiplicative inverse of y),
assuming that the multiplicative inverse of y exists. However, if
multiplication does not commute, “x times (the multiplicative inverse of
y)” need not equal “(the multiplicative inverse of y) times x.” The C++
binary <code>operator/</code> does not give callers a way to distinguish
between these two cases.</p>
<p>This suggests four ways to express “ordered division.”</p>
<ol type="1">
<li><p>Explicitly divide one by the quotient: <code>x * (1/y)</code>, or
<code>(1/y) * x</code></p></li>
<li><p>Like (2), but instead of using literal <code>1</code>, get “one”
as a <code>value_type</code> input to the algorithm:
<code>x * (one/y)</code>, or <code>(one/y) * x</code></p></li>
<li><p><code>inverse</code> as a unary callable input to the algorithm:
<code>x * inverse(y)</code>, or <code>inverse(y) * x</code></p></li>
<li><p><code>divide</code> as a binary callable input to the algorithm:
<code>divide(x, y)</code>, or <code>divide(y, x)</code></p></li>
</ol>
<p>Both SG6 small group (in its review of this proposal on 2022/06/09)
and the authors prefer Way (4), the <code>divide</code> binary callable
input. The binary callable would be optional, and ordinary binary
<code>operator/</code> would be used as the default. This would imitate
existing Standard Library algorithms like <code>reduce</code>, with its
optional <code>BinaryOp</code> that defaults to addition. For
mixed-precision computation, users would need to avoid
<code>std::divides</code>, as its two parameters and its return type all
have the same types. However, the obvious
<code>[] (const auto&amp; x, const auto&amp; y) { return x / y; }</code>
would work just fine. Way (4) also preserves the original rounding
behavior for types with commutative multiplication.</p>
<p>The main disadvantage of the other approaches is that they would
change rounding behavior for floating-point types. They also require two
operations – computing an inverse, and multiplication – rather than one.
“Ordered division” may actually be the operation users want, and the
“inverse” might be just a byproduct. This is the case for square
matrices, where users often “compute an inverse” only because they want
to solve a linear system. Each of the other approaches has its own other
disadvantages.</p>
<ul>
<li><p>Way (1) would assume that an overloaded
<code>operator/(int, value_type)</code> exists, and that the literal
<code>1</code> behaves like a multiplicative identity. In practice, not
all custom number types may have defined mixed arithmetic with
<code>int</code>.</p></li>
<li><p>Way (2) would complicate the interface. Users might make the
mistake of passing in literal <code>1</code> (of type <code>int</code>)
or <code>1.0</code> (of type <code>double</code>) as the value of one,
thus leading to Way (1)’s issues.</p></li>
<li><p>Way (3) would again complicate the interface. Users would be
tempted to use <code>[](const auto&amp; y) { return 1 / y; }</code> as
the inverse function, thus leading back to Way (1)’s issues.</p></li>
</ul>
<h1 data-number="12" id="future-work"><span class="header-section-number">12</span> Future work<a href="#future-work" class="self-link"></a></h1>
<p>Summary:</p>
<ol type="1">
<li><p>Consider generalizing function parameters to take any type that
implements a customization point for getting an <code>mdspan</code>
viewing its elements. This includes <code>mdarray</code> (see
P1684).</p></li>
<li><p>Add batched linear algebra overloads.</p></li>
</ol>
<h2 data-number="12.1" id="generalize-function-parameters"><span class="header-section-number">12.1</span> Generalize function
parameters<a href="#generalize-function-parameters" class="self-link"></a></h2>
<p>Our functions differ from the C++ Standard algorithms, in that they
take a concrete type <code>mdspan</code> with template parameters,
rather than any type that satisfies a concept. We think that the
template parameters of <code>mdspan</code> fully describe the
multidimensional equivalent of a multipass iterator, and that
“conceptification” of multidimensional arrays would unnecessarily delay
this proposal.</p>
<p>In a future proposal, we may consider generalizing our function’s
template parameters, to permit any type besides <code>mdspan</code> that
implements the <code>get_mdspan</code> customization point, as long as
the return value of <code>get_mdspan</code> satisfies the current
requirements. <code>get_mdspan</code> would return an
<code>mdspan</code> that views its argument’s data.</p>
<p>The <code>mdarray</code> class, proposed in
<a href="https://wg21.link/p1684">P1684</a>, is the container analog of
<code>mdspan</code>. It is a new kind of container, with the same copy
behavior as containers like <code>vector</code>. It will be possible to
get an <code>mdspan</code> that views an <code>mdarray</code>. Previous
versions of this proposal included function overloads that took
<code>mdarray</code> directly. The goals were user convenience, and to
avoid any potential overhead of conversion to <code>mdspan</code>,
especially for very small matrices and vectors. In a future revision of
P1684, <code>mdarray</code> will implement a customization point
<code>view</code> (final name yet to be decided), that returns an
<code>mdspan</code> viewing the elements of the <code>mdarray</code>.
This would let users use <code>mdarray</code> directly in our functions.
This customization point approach would also simplify using our
functions with other matrix and vector types, such as those proposed by
P1385. Implementations may optionally add direct overloads of our
functions for <code>mdarray</code> or other types. This would address
any concerns about overhead of converting from <code>mdarray</code> to
<code>mdspan</code>.</p>
<h2 data-number="12.2" id="batched-linear-algebra"><span class="header-section-number">12.2</span> Batched linear algebra<a href="#batched-linear-algebra" class="self-link"></a></h2>
<p>We plan to write a separate proposal that will add “batched” versions
of linear algebra functions to this proposal. “Batched” linear algebra
functions solve many independent problems all at once, in a single
function call. For discussion, see Section 6.2 of our background paper
<a href="https://wg21.link/p1417r0">P1417R0</a>. Batched interfaces have
the following advantages:</p>
<ul>
<li><p>They expose more parallelism and vectorization opportunities for
many small linear algebra operations.</p></li>
<li><p>They are useful for many different fields, including machine
learning.</p></li>
<li><p>Hardware vendors currently offer both hardware features and
optimized software libraries to support batched linear algebra.</p></li>
<li><p>There is an ongoing <a href="http://icl.utk.edu/bblas/">interface
standardization effort</a>, in which we participate.</p></li>
</ul>
<p>The <code>mdspan</code> data structure makes it easy to represent a
batch of linear algebra objects, and to optimize their data layout.</p>
<p>With few exceptions, the extension of this proposal to support
batched operations will not require new functions or interface changes.
Only the requirements on functions will change. Output arguments can
have an additional rank; if so, then the leftmost extent will refer to
the batch dimension. Input arguments may also have an additional rank to
match; if they do not, the function will use (“broadcast”) the same
input argument for all the output arguments in the batch.</p>
<h1 data-number="13" id="data-structures-and-utilities-borrowed-from-other-proposals"><span class="header-section-number">13</span> Data structures and utilities
borrowed from other proposals<a href="#data-structures-and-utilities-borrowed-from-other-proposals" class="self-link"></a></h1>
<h2 data-number="13.1" id="mdspan"><span class="header-section-number">13.1</span> <code>mdspan</code><a href="#mdspan" class="self-link"></a></h2>
<p>This proposal depends on P0009 and follow-on papers that were voted
into the current C++ Standard draft. P0009’s main class is
<code>mdspan</code>, which is a “view” (in the sense of
<code>span</code>) of a multidimensional array. The rank (number of
dimensions) is fixed at compile time. Users may specify some dimensions
at run time and others at compile time; the type of the
<code>mdspan</code> expresses this. <code>mdspan</code> also has two
customization points:</p>
<ul>
<li><p><code>Layout</code> expresses the array’s memory layout: e.g.,
row-major (C++ style), column-major (Fortran style), or strided. We use
a custom <code>Layout</code> later in this paper to implement a
“transpose view” of an existing <code>mdspan</code>.</p></li>
<li><p><code>Accessor</code> defines the storage handle
(<code>data_handle_type</code>) stored in the <code>mdspan</code>, as
well as the reference type returned by its access operator. This is an
extension point for modifying how access happens, for example by using
<code>atomic_ref</code> to get atomic access to every element. We use
custom <code>Accessor</code>s later in this paper to implement “scaled
views” and “conjugated views” of an existing
<code>mdspan</code>.</p></li>
</ul>
<h2 data-number="13.2" id="new-mdspan-layouts-in-this-proposal"><span class="header-section-number">13.2</span> New <code>mdspan</code>
layouts in this proposal<a href="#new-mdspan-layouts-in-this-proposal" class="self-link"></a></h2>
<p>Our proposal uses the layout mapping policy of <code>mdspan</code> in
order to represent different matrix and vector data layouts. The current
C++ Standard draft includes three layouts: <code>layout_left</code>,
<code>layout_right</code>, and <code>layout_stride</code>.
<a href="https://wg21.link/p2642r2">P2642R2</a> includes
<code>layout_left_padded</code> and <code>layout_right_padded</code>.
These two layouts represent exactly the data layout assumed by the
General (GE) matrix type in the BLAS’ C and Fortran bindings. They have
has two advantages:</p>
<ol type="1">
<li><p>Unlike <code>layout_left</code> and <code>layout_right</code>,
any “submatrix” (subspan of consecutive rows and consecutive columns) of
a matrix with <code>layout_left_padded</code> resp.
<code>layout_right_padded</code> layout also has
<code>layout_left_padded</code> resp. <code>layout_right_padded</code>
layout.</p></li>
<li><p>Unlike <code>layout_stride</code>, the two layouts always have
compile-time unit stride in one of the matrix’s two extents.</p></li>
</ol>
<p>BLAS functions call the possibly nonunit stride of the matrix the
“leading dimension” of that matrix. For example, a BLAS function
argument corresponding to the leading dimension of the matrix
<code>A</code> is called <code>LDA</code>, for “leading dimension of the
matrix A.”</p>
<p>This proposal introduces a new layout,
<code>layout_blas_packed</code>. This describes the layout used by the
BLAS’ Symmetric Packed (SP), Hermitian Packed (HP), and Triangular
Packed (TP) “types.” The <code>layout_blas_packed</code> class has a
“tag” template parameter that controls its properties; see below.</p>
<p>We do not include layouts for unpacked “types,” such as Symmetric
(SY), Hermitian (HE), and Triangular (TR). Our paper
<a href="https://wg21.link/p1674">P1674</a>. explains our reasoning. In
summary: Their actual layout – the arrangement of matrix elements in
memory – is the same as General. The only differences are constraints on
what entries of the matrix algorithms may access, and assumptions about
the matrix’s mathematical properties. Trying to express those
constraints or assumptions as “layouts” or “accessors” violates the
spirit (and sometimes the law) of <code>mdspan</code>. We address these
different matrix types with different function names.</p>
<p>The packed matrix “types” do describe actual arrangements of matrix
elements in memory that are not the same as in General. This is why we
provide <code>layout_blas_packed</code>. Note that
<code>layout_blas_packed</code> is the first addition to the existing
layouts that is neither always unique, nor always strided.</p>
<p>Algorithms cannot be written generically if they permit output
arguments with nonunique layouts. Nonunique output arguments require
specialization of the algorithm to the layout, since there’s no way to
know generically at compile time what indices map to the same matrix
element. Thus, we will impose the following rule: Any
<code>mdspan</code> output argument to our functions must always have
unique layout (<code>is_always_unique()</code> is <code>true</code>),
unless otherwise specified.</p>
<p>Some of our functions explicitly require outputs with specific
nonunique layouts. This includes low-rank updates to symmetric or
Hermitian matrices.</p>
<h1 data-number="14" id="acknowledgments"><span class="header-section-number">14</span> Acknowledgments<a href="#acknowledgments" class="self-link"></a></h1>
<p>Sandia National Laboratories is a multimission laboratory managed and
operated by National Technology &amp; Engineering Solutions of Sandia,
LLC, a wholly owned subsidiary of Honeywell International, Inc., for the
U.S. Department of Energy’s National Nuclear Security Administration
under contract DE-NA0003525.</p>
<p>Special thanks to Bob Steagall and Guy Davidson for boldly leading
the charge to add linear algebra to the C++ Standard Library, and for
many fruitful discussions. Thanks also to Andrew Lumsdaine for his
pioneering efforts and history lessons. In addition, I very much
appreciate feedback from Davis Herring on constraints wording.</p>
<h1 data-number="15" id="references"><span class="header-section-number">15</span> References<a href="#references" class="self-link"></a></h1>
<h2 data-number="15.1" id="references-by-coathors"><span class="header-section-number">15.1</span> References by coathors<a href="#references-by-coathors" class="self-link"></a></h2>
<ul>
<li><p>G. Ballard, E. Carson, J. Demmel, M. Hoemmen, N. Knight, and O.
Schwartz, <a href="https://doi.org/10.1017/S0962492914000038">“Communication lower
bounds and optimal algorithms for numerical linear algebra,”</a>,
<em>Acta Numerica</em>, Vol. 23, May 2014, pp. 1-155.</p></li>
<li><p>C. Trott, D. S. Hollman, D. Lebrun-Grande, M. Hoemmen, D.
Sunderland, H. C. Edwards, B. A. Lelbach, M. Bianco, B. Sander, A.
Iliopoulos, J. Michopoulos, and N. Liber, “<code>mdspan</code>,”
<a href="https://wg21.link/p0009r16">P0009R16</a>, Mar. 2022. The
authors anticipate release of R17 in the next mailing.</p></li>
<li><p>G. Davidson, M. Hoemmen, D. S. Hollman, B. Steagall, and C.
Trott, <a href="https://wg21.link/p1891r0">P1891R0</a>,
Oct. 2019.</p></li>
<li><p>M. Hoemmen, D. S. Hollman, and C. Trott, “Evolving a Standard C++
Linear Algebra Library from the BLAS,”
<a href="https://wg21.link/p1674r2">P1674R2</a>, May 2022.</p></li>
<li><p>M. Hoemmen, J. Badwaik, M. Brucher, A. Iliopoulos, and J.
Michopoulos, “Historical lessons for C++ linear algebra library
standardization,” <a href="https://wg21.link/p1417r0">P1417R0</a>,
Jan. 2019.</p></li>
<li><p>M. Hoemmen, D. S. Hollman, C. Jabot, I. Muerte, and C. Trott,
“Multidimensional subscript operator,”
<a href="https://wg21.link/p2128r6">P2128R6</a>, Sep. 2021.</p></li>
<li><p>C. Trott, D. S. Hollman, M. Hoemmen, and D. Sunderland,
“<code>mdarray</code>: An Owning Multidimensional Array Analog of
<code>mdspan</code>”, <a href="https://wg21.link/p1684r1">P1684R1</a>,
Mar. 2022.</p></li>
<li><p>D. S. Hollman, C. Kohlhoff, B. A. Lelbach, J. Hoberock, G. Brown,
and M. Dominiak, “A General Property Customization Mechanism,”
<a href="https://wg21.link/p1393r0">P1393R0</a>, Jan. 2019.</p></li>
</ul>
<h2 data-number="15.2" id="other-references"><span class="header-section-number">15.2</span> Other references<a href="#other-references" class="self-link"></a></h2>
<ul>
<li><p>E. Anderson, “Algorithm 978: Safe Scaling in the Level 1 BLAS,”
<em>ACM Transactions on Mathematical Software</em>, Vol. 44, pp. 1-28,
2017.</p></li>
<li><p><a href="http://netlib.org/blas/blast-forum/blas-report.pdf">“Basic Linear
Algebra Subprograms Technical (BLAST) Forum Standard,”</a>
<em>International Journal of High Performance Applications and
Supercomputing</em>, Vol. 16, No. 1, Spring 2002.</p></li>
<li><p>L. S. Blackford, J. Demmel, J. Dongarra, I. Duff, S. Hammarling,
G. Henry, M. Heroux, L. Kaufman, A. Lumsdaine, A. Petitet, R. Pozo, K.
Remington, and R. C. Whaley, <a href="https://doi.org/10.1145/567806.567807">“An updated set of basic
linear algebra subprograms (BLAS),”</a> <em>ACM Transactions on
Mathematical Software</em>, Vol. 28, No. 2, Jun. 2002,
pp. 135-151.</p></li>
<li><p>J. L. Blue, “A Portable Fortran Program to Find the Euclidean
Norm of a Vector,” <em>ACM Transactions on Mathematical Software</em>,
Vol. 4, pp. 15-23, 1978.</p></li>
<li><p>B. D. Craven,
<a href="https://doi.org/10.1017/S1446788700007588">“Complex symmetric
matrices”</a>, <em>Journal of the Australian Mathematical Society</em>,
Vol. 10, No. 3-4, Nov. 1969, pp. 341–354.</p></li>
<li><p>E. Chow and A. Patel, “Fine-Grained Parallel Incomplete LU
Factorization”, <em>SIAM J. Sci. Comput.</em>, Vol. 37, No. 2,
C169-C193, 2015.</p></li>
<li><p>G. Davidson and B. Steagall, “A proposal to add linear algebra
support to the C++ standard library,”
<a href="https://wg21.link/p1385r6">P1385R6</a>, Mar. 2020.</p></li>
<li><p>B. Dawes, H. Hinnant, B. Stroustrup, D. Vandevoorde, and M. Wong,
“Direction for ISO C++,”
<a href="https://wg21.link/p0939r4">P0939R4</a>, Oct. 2019.</p></li>
<li><p>J. Demmel, “Applied Numerical Linear Algebra,” Society for
Industrial and Applied Mathematics, Philadelphia, PA, 1997, ISBN
0-89871-389-7.</p></li>
<li><p>J. Demmel, I. Dumitriu, and O. Holtz, “Fast linear algebra is
stable,” <em>Numerische Mathematik</em> 108 (59-91), 2007.</p></li>
<li><p>J. Demmel and H. D. Nguyen, “Fast Reproducible Floating-Point
Summation,” 2013 IEEE 21st Symposium on Computer Arithmetic, 2013,
pp. 163-172, doi: 10.1109/ARITH.2013.9.</p></li>
<li><p>J. Dongarra, J. Du Croz, S. Hammarling, and I. Duff,
<a href="https://dl.acm.org/doi/10.1145/77626.79170">“A set of level 3
basic linear algebra subprograms,”</a> <em>ACM Transactions on
Mathematical Software</em>, Vol. 16, No. 1, pp. 1-17,
Mar. 1990.</p></li>
<li><p>J. Dongarra, R. Pozo, and D. Walker, “LAPACK++: A Design Overview
of Object-Oriented Extensions for High Performance Linear Algebra,” in
Proceedings of Supercomputing ’93, IEEE Computer Society Press, 1993,
pp. 162-171.</p></li>
<li><p>M. Gates, P. Luszczek, A. Abdelfattah, J. Kurzak, J. Dongarra, K.
Arturov, C. Cecka, and C. Freitag,
<a href="https://www.icl.utk.edu/files/publications/2017/icl-utk-1031-2017.pdf">“C++
API for BLAS and LAPACK,”</a> SLATE Working Notes, Innovative Computing
Laboratory, University of Tennessee Knoxville, Feb. 2018.</p></li>
<li><p>K. Goto and R. A. van de Geijn, <a href="https://doi.org/10.1145/1356052.1356053">“Anatomy of
high-performance matrix multiplication,”</a>, <em>ACM Transactions on
Mathematical Software</em> (TOMS), Vol. 34, No. 3, May 2008.</p></li>
<li><p>J. Hoberock, “Integrating Executors with Parallel Algorithms,”
<a href="https://wg21.link/p1019r2">P1019R2</a>, Jan. 2019.</p></li>
<li><p>N. A. Josuttis, “The C++ Standard Library: A Tutorial and
Reference,” Addison-Wesley, 1999.</p></li>
<li><p>M. Kretz, “Data-Parallel Vector Types &amp; Operations,”
<a href="https://wg21.link/p0214r9">P0214R9</a>, Mar. 2018.</p></li>
<li><p>A. J. Perlis, “Epigrams on programming,” SIGPLAN Notices, Vol.
17, No. 9, pp. 7-13, 1982.</p></li>
<li><p>G. Strang, “Introduction to Linear Algebra,” 5th Edition,
Wellesley - Cambridge Press, 2016, ISBN 978-0-9802327-7-6, x+574
pages.</p></li>
<li><p>D. Vandevoorde and N. A. Josuttis, “C++ Templates: The Complete
Guide,” Addison-Wesley Professional, 2003.</p></li>
</ul>
<h1 data-number="16" id="wording"><span class="header-section-number">16</span> Wording<a href="#wording" class="self-link"></a></h1>
<blockquote>
<p>Text in blockquotes is not proposed wording, but rather instructions
for generating proposed wording. The � character is used to denote a
placeholder section number which the editor shall determine. First,
apply all wording from P2642R2. (This proposal is a “rebase” atop the
changes proposed by P2642R2.) At the end of Table � (“Numerics library
summary”) in <em>[numerics.general]</em>, add the following: [linalg],
Linear algebra, <code>&lt;linalg&gt;</code>. At the end of
<em>[numerics]</em> (after subsection 28.8 <em>[numbers]</em>), add all
the material that follows.</p>
</blockquote>
<h2 data-number="16.1" id="add-subsection-28.9-linalg-with-the-following"><span class="header-section-number">16.1</span> Add subsection 28.9 [linalg]
with the following<a href="#add-subsection-28.9-linalg-with-the-following" class="self-link"></a></h2>
<p><b>28.9 Basic linear algebra algorithms [linalg]</b></p>
<p><b>28.9.1 Overview [linalg.overview] </b></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Subclause [linalg] defines basic linear algebra algorithms. The
algorithms that access the elements of arrays view the arrays’ elements
through <code>mdspan</code> [mdspan].</p>
<p><b>28.9.2 Header <code>&lt;linalg&gt;</code> synopsis
[linalg.syn]</b></p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>linalg <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.tags.order], storage order tags</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> column_major_t;</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> column_major_t column_major;</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> row_major_t;</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> row_major_t row_major;</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.tags.triangle], triangle tags</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> upper_triangle_t;</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> upper_triangle_t upper_triangle;</span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> lower_triangle_t;</span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> lower_triangle_t lower_triangle;</span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.tags.diagonal], diagonal tags</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> implicit_unit_diagonal_t;</span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> implicit_unit_diagonal_t implicit_unit_diagonal;</span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> explicit_diagonal_t;</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> explicit_diagonal_t explicit_diagonal;</span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.layouts.packed], class template layout_blas_packed</span></span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Triangle,</span>
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> StorageOrder<span class="op">&gt;</span></span>
<span id="cb6-23"><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> layout_blas_packed;</span>
<span id="cb6-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-25"><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.scaled.conj], exposition-only function object <em>conj-if-needed</em></span></span>
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-27"><a href="#cb6-27" aria-hidden="true" tabindex="-1"></a><span class="co">/* see-below */</span> <em>conj-if-needed</em>;</span>
<span id="cb6-28"><a href="#cb6-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-29"><a href="#cb6-29" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.scaled.base], exposition-only function and class templates</span></span>
<span id="cb6-30"><a href="#cb6-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-31"><a href="#cb6-31" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <em>proxy-reference-base</em>; <span class="co">// <em>exposition only</em></span></span>
<span id="cb6-32"><a href="#cb6-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-33"><a href="#cb6-33" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Reference, <span class="kw">class</span> Value, <span class="kw">class</span> Derived<span class="op">&gt;</span></span>
<span id="cb6-34"><a href="#cb6-34" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <em>proxy-reference</em>; <span class="co">// <em>exposition only</em></span></span>
<span id="cb6-35"><a href="#cb6-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-36"><a href="#cb6-36" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.scaled.accessor_scaled], class template accessor_scaled</span></span>
<span id="cb6-37"><a href="#cb6-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-38"><a href="#cb6-38" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ScalingFactor,</span>
<span id="cb6-39"><a href="#cb6-39" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb6-40"><a href="#cb6-40" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> accessor_scaled;</span>
<span id="cb6-41"><a href="#cb6-41" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-42"><a href="#cb6-42" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.scaled.scaled], scaled in-place transformation</span></span>
<span id="cb6-43"><a href="#cb6-43" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ScalingFactor,</span>
<span id="cb6-44"><a href="#cb6-44" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> ElementType,</span>
<span id="cb6-45"><a href="#cb6-45" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Extents,</span>
<span id="cb6-46"><a href="#cb6-46" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Layout,</span>
<span id="cb6-47"><a href="#cb6-47" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb6-48"><a href="#cb6-48" aria-hidden="true" tabindex="-1"></a><span class="co">/* see-below */</span></span>
<span id="cb6-49"><a href="#cb6-49" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> scaled<span class="op">(</span></span>
<span id="cb6-50"><a href="#cb6-50" aria-hidden="true" tabindex="-1"></a>  ScalingFactor scaling_factor,</span>
<span id="cb6-51"><a href="#cb6-51" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> mdspan<span class="op">&lt;</span>ElementType, Extents, Layout, Accessor<span class="op">&gt;&amp;</span> x<span class="op">)</span>;</span>
<span id="cb6-52"><a href="#cb6-52" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-53"><a href="#cb6-53" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.conj.accessor_conjugate], class template accessor_conjugate</span></span>
<span id="cb6-54"><a href="#cb6-54" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb6-55"><a href="#cb6-55" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> accessor_conjugate;</span>
<span id="cb6-56"><a href="#cb6-56" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-57"><a href="#cb6-57" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.conj.conjugated], conjugated in-place transformation</span></span>
<span id="cb6-58"><a href="#cb6-58" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType,</span>
<span id="cb6-59"><a href="#cb6-59" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Extents,</span>
<span id="cb6-60"><a href="#cb6-60" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Layout,</span>
<span id="cb6-61"><a href="#cb6-61" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb6-62"><a href="#cb6-62" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> conjugated<span class="op">(</span></span>
<span id="cb6-63"><a href="#cb6-63" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span>ElementType, Extents, Layout, Accessor<span class="op">&gt;</span> a<span class="op">)</span>;</span>
<span id="cb6-64"><a href="#cb6-64" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-65"><a href="#cb6-65" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.transp.layout_transpose], class template layout_transpose</span></span>
<span id="cb6-66"><a href="#cb6-66" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Layout<span class="op">&gt;</span></span>
<span id="cb6-67"><a href="#cb6-67" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> layout_transpose;</span>
<span id="cb6-68"><a href="#cb6-68" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-69"><a href="#cb6-69" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.transp.transposed], transposed in-place transformation</span></span>
<span id="cb6-70"><a href="#cb6-70" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType,</span>
<span id="cb6-71"><a href="#cb6-71" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Extents,</span>
<span id="cb6-72"><a href="#cb6-72" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Layout,</span>
<span id="cb6-73"><a href="#cb6-73" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb6-74"><a href="#cb6-74" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> transposed<span class="op">(</span></span>
<span id="cb6-75"><a href="#cb6-75" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span>ElementType, Extents, Layout, Accessor<span class="op">&gt;</span> a<span class="op">)</span>;</span>
<span id="cb6-76"><a href="#cb6-76" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-77"><a href="#cb6-77" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.conj_transp],</span></span>
<span id="cb6-78"><a href="#cb6-78" aria-hidden="true" tabindex="-1"></a><span class="co">// conjugated transposed in-place transformation</span></span>
<span id="cb6-79"><a href="#cb6-79" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType,</span>
<span id="cb6-80"><a href="#cb6-80" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Extents,</span>
<span id="cb6-81"><a href="#cb6-81" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Layout,</span>
<span id="cb6-82"><a href="#cb6-82" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb6-83"><a href="#cb6-83" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> conjugate_transposed<span class="op">(</span></span>
<span id="cb6-84"><a href="#cb6-84" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span>ElementType, Extents, Layout, Accessor<span class="op">&gt;</span> a<span class="op">)</span>;</span>
<span id="cb6-85"><a href="#cb6-85" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-86"><a href="#cb6-86" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.concepts], exposition-only concepts and traits</span></span>
<span id="cb6-87"><a href="#cb6-87" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-88"><a href="#cb6-88" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-89"><a href="#cb6-89" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>is-mdspan</em>; <span class="co">// exposition only</span></span>
<span id="cb6-90"><a href="#cb6-90" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-91"><a href="#cb6-91" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-92"><a href="#cb6-92" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>in-vector</em>; <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb6-93"><a href="#cb6-93" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-94"><a href="#cb6-94" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-95"><a href="#cb6-95" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>out-vector</em>; <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb6-96"><a href="#cb6-96" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-97"><a href="#cb6-97" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-98"><a href="#cb6-98" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>inout-vector</em>; <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb6-99"><a href="#cb6-99" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-100"><a href="#cb6-100" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-101"><a href="#cb6-101" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>in-matrix</em>; <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb6-102"><a href="#cb6-102" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-103"><a href="#cb6-103" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-104"><a href="#cb6-104" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>out-matrix</em>; <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb6-105"><a href="#cb6-105" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-106"><a href="#cb6-106" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-107"><a href="#cb6-107" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>inout-matrix</em>; <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb6-108"><a href="#cb6-108" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-109"><a href="#cb6-109" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-110"><a href="#cb6-110" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>possibly-packed-inout-matrix</em>; <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb6-111"><a href="#cb6-111" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-112"><a href="#cb6-112" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-113"><a href="#cb6-113" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>in-object</em>; <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb6-114"><a href="#cb6-114" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-115"><a href="#cb6-115" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-116"><a href="#cb6-116" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>out-object</em>; <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb6-117"><a href="#cb6-117" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-118"><a href="#cb6-118" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-119"><a href="#cb6-119" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>inout-object</em>; <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb6-120"><a href="#cb6-120" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-121"><a href="#cb6-121" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs], algorithms</span></span>
<span id="cb6-122"><a href="#cb6-122" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-123"><a href="#cb6-123" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.givens.lartg], compute Givens rotation</span></span>
<span id="cb6-124"><a href="#cb6-124" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-125"><a href="#cb6-125" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb6-126"><a href="#cb6-126" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> givens_rotation_setup_result <span class="op">{</span></span>
<span id="cb6-127"><a href="#cb6-127" aria-hidden="true" tabindex="-1"></a>  Real c;</span>
<span id="cb6-128"><a href="#cb6-128" aria-hidden="true" tabindex="-1"></a>  Real s;</span>
<span id="cb6-129"><a href="#cb6-129" aria-hidden="true" tabindex="-1"></a>  Real r;</span>
<span id="cb6-130"><a href="#cb6-130" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb6-131"><a href="#cb6-131" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb6-132"><a href="#cb6-132" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> givens_rotation_setup_result<span class="op">&lt;</span>complex<span class="op">&lt;</span>Real<span class="op">&gt;&gt;</span> <span class="op">{</span></span>
<span id="cb6-133"><a href="#cb6-133" aria-hidden="true" tabindex="-1"></a>  Real c;</span>
<span id="cb6-134"><a href="#cb6-134" aria-hidden="true" tabindex="-1"></a>  complex<span class="op">&lt;</span>Real<span class="op">&gt;</span> s;</span>
<span id="cb6-135"><a href="#cb6-135" aria-hidden="true" tabindex="-1"></a>  complex<span class="op">&lt;</span>Real<span class="op">&gt;</span> r;</span>
<span id="cb6-136"><a href="#cb6-136" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb6-137"><a href="#cb6-137" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb6-138"><a href="#cb6-138" aria-hidden="true" tabindex="-1"></a>givens_rotation_setup_result<span class="op">&lt;</span>Real<span class="op">&gt;</span></span>
<span id="cb6-139"><a href="#cb6-139" aria-hidden="true" tabindex="-1"></a>givens_rotation_setup<span class="op">(</span><span class="kw">const</span> Real a,</span>
<span id="cb6-140"><a href="#cb6-140" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">const</span> Real b<span class="op">)</span>;</span>
<span id="cb6-141"><a href="#cb6-141" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb6-142"><a href="#cb6-142" aria-hidden="true" tabindex="-1"></a>givens_rotation_setup_result<span class="op">&lt;</span>complex<span class="op">&lt;</span>Real<span class="op">&gt;&gt;</span></span>
<span id="cb6-143"><a href="#cb6-143" aria-hidden="true" tabindex="-1"></a>givens_rotation_setup<span class="op">(</span><span class="kw">const</span> complex<span class="op">&lt;</span>Real<span class="op">&gt;&amp;</span> a,</span>
<span id="cb6-144"><a href="#cb6-144" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">const</span> complex<span class="op">&lt;</span>Real<span class="op">&gt;&amp;</span> b<span class="op">)</span>;</span>
<span id="cb6-145"><a href="#cb6-145" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-146"><a href="#cb6-146" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.givens.rot], apply computed Givens rotation</span></span>
<span id="cb6-147"><a href="#cb6-147" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>inout-vector</em> InOutVec1,</span>
<span id="cb6-148"><a href="#cb6-148" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec2,</span>
<span id="cb6-149"><a href="#cb6-149" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb6-150"><a href="#cb6-150" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> givens_rotation_apply<span class="op">(</span></span>
<span id="cb6-151"><a href="#cb6-151" aria-hidden="true" tabindex="-1"></a>  InOutVec1 x,</span>
<span id="cb6-152"><a href="#cb6-152" aria-hidden="true" tabindex="-1"></a>  InOutVec2 y,</span>
<span id="cb6-153"><a href="#cb6-153" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Real c,</span>
<span id="cb6-154"><a href="#cb6-154" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Real s<span class="op">)</span>;</span>
<span id="cb6-155"><a href="#cb6-155" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-156"><a href="#cb6-156" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec1,</span>
<span id="cb6-157"><a href="#cb6-157" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec2,</span>
<span id="cb6-158"><a href="#cb6-158" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb6-159"><a href="#cb6-159" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> givens_rotation_apply<span class="op">(</span></span>
<span id="cb6-160"><a href="#cb6-160" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-161"><a href="#cb6-161" aria-hidden="true" tabindex="-1"></a>  InOutVec1 x,</span>
<span id="cb6-162"><a href="#cb6-162" aria-hidden="true" tabindex="-1"></a>  InOutVec2 y,</span>
<span id="cb6-163"><a href="#cb6-163" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Real c,</span>
<span id="cb6-164"><a href="#cb6-164" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Real s<span class="op">)</span>;</span>
<span id="cb6-165"><a href="#cb6-165" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>inout-vector</em> InOutVec1,</span>
<span id="cb6-166"><a href="#cb6-166" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec2,</span>
<span id="cb6-167"><a href="#cb6-167" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb6-168"><a href="#cb6-168" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> givens_rotation_apply<span class="op">(</span></span>
<span id="cb6-169"><a href="#cb6-169" aria-hidden="true" tabindex="-1"></a>  InOutVec1 x,</span>
<span id="cb6-170"><a href="#cb6-170" aria-hidden="true" tabindex="-1"></a>  InOutVec2 y,</span>
<span id="cb6-171"><a href="#cb6-171" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Real c,</span>
<span id="cb6-172"><a href="#cb6-172" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> complex<span class="op">&lt;</span>Real<span class="op">&gt;</span> s<span class="op">)</span>;</span>
<span id="cb6-173"><a href="#cb6-173" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-174"><a href="#cb6-174" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec1,</span>
<span id="cb6-175"><a href="#cb6-175" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec2,</span>
<span id="cb6-176"><a href="#cb6-176" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb6-177"><a href="#cb6-177" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> givens_rotation_apply<span class="op">(</span></span>
<span id="cb6-178"><a href="#cb6-178" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-179"><a href="#cb6-179" aria-hidden="true" tabindex="-1"></a>  InOutVec1 x,</span>
<span id="cb6-180"><a href="#cb6-180" aria-hidden="true" tabindex="-1"></a>  InOutVec2 y,</span>
<span id="cb6-181"><a href="#cb6-181" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Real c,</span>
<span id="cb6-182"><a href="#cb6-182" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> complex<span class="op">&lt;</span>Real<span class="op">&gt;</span> s<span class="op">)</span>;</span>
<span id="cb6-183"><a href="#cb6-183" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-184"><a href="#cb6-184" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.swap], swap elements</span></span>
<span id="cb6-185"><a href="#cb6-185" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>inout-object</em> InOutObj1,</span>
<span id="cb6-186"><a href="#cb6-186" aria-hidden="true" tabindex="-1"></a>         <em>inout-object</em> InOutObj2<span class="op">&gt;</span></span>
<span id="cb6-187"><a href="#cb6-187" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> swap_elements<span class="op">(</span>InOutObj1 x,</span>
<span id="cb6-188"><a href="#cb6-188" aria-hidden="true" tabindex="-1"></a>                   InOutObj2 y<span class="op">)</span>;</span>
<span id="cb6-189"><a href="#cb6-189" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-190"><a href="#cb6-190" aria-hidden="true" tabindex="-1"></a>         <em>inout-object</em> InOutObj1,</span>
<span id="cb6-191"><a href="#cb6-191" aria-hidden="true" tabindex="-1"></a>         <em>inout-object</em> InOutObj2<span class="op">&gt;</span></span>
<span id="cb6-192"><a href="#cb6-192" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> swap_elements<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-193"><a href="#cb6-193" aria-hidden="true" tabindex="-1"></a>                   InOutObj1 x,</span>
<span id="cb6-194"><a href="#cb6-194" aria-hidden="true" tabindex="-1"></a>                   InOutObj2 y<span class="op">)</span>;</span>
<span id="cb6-195"><a href="#cb6-195" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-196"><a href="#cb6-196" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.scal], multiply elements by scalar</span></span>
<span id="cb6-197"><a href="#cb6-197" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Scalar,</span>
<span id="cb6-198"><a href="#cb6-198" aria-hidden="true" tabindex="-1"></a>         <em>inout-object</em> InOutObj<span class="op">&gt;</span></span>
<span id="cb6-199"><a href="#cb6-199" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> scale<span class="op">(</span><span class="kw">const</span> Scalar alpha,</span>
<span id="cb6-200"><a href="#cb6-200" aria-hidden="true" tabindex="-1"></a>           InOutObj x<span class="op">)</span>;</span>
<span id="cb6-201"><a href="#cb6-201" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-202"><a href="#cb6-202" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Scalar,</span>
<span id="cb6-203"><a href="#cb6-203" aria-hidden="true" tabindex="-1"></a>         <em>inout-object</em> InOutObj<span class="op">&gt;</span></span>
<span id="cb6-204"><a href="#cb6-204" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> scale<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-205"><a href="#cb6-205" aria-hidden="true" tabindex="-1"></a>           <span class="kw">const</span> Scalar alpha,</span>
<span id="cb6-206"><a href="#cb6-206" aria-hidden="true" tabindex="-1"></a>           InOutObj x<span class="op">)</span>;</span>
<span id="cb6-207"><a href="#cb6-207" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-208"><a href="#cb6-208" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.copy], copy elements</span></span>
<span id="cb6-209"><a href="#cb6-209" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-object</em> InObj,</span>
<span id="cb6-210"><a href="#cb6-210" aria-hidden="true" tabindex="-1"></a>         <em>out-object</em> OutObj<span class="op">&gt;</span></span>
<span id="cb6-211"><a href="#cb6-211" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> copy<span class="op">(</span>InObj x,</span>
<span id="cb6-212"><a href="#cb6-212" aria-hidden="true" tabindex="-1"></a>          OutObj y<span class="op">)</span>;</span>
<span id="cb6-213"><a href="#cb6-213" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-214"><a href="#cb6-214" aria-hidden="true" tabindex="-1"></a>         <em>in-object</em> InObj,</span>
<span id="cb6-215"><a href="#cb6-215" aria-hidden="true" tabindex="-1"></a>         <em>out-object</em> OutObj<span class="op">&gt;</span></span>
<span id="cb6-216"><a href="#cb6-216" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> copy<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-217"><a href="#cb6-217" aria-hidden="true" tabindex="-1"></a>          InObj x,</span>
<span id="cb6-218"><a href="#cb6-218" aria-hidden="true" tabindex="-1"></a>          OutObj y<span class="op">)</span>;</span>
<span id="cb6-219"><a href="#cb6-219" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-220"><a href="#cb6-220" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.add], add elementwise</span></span>
<span id="cb6-221"><a href="#cb6-221" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-object</em> InObj1,</span>
<span id="cb6-222"><a href="#cb6-222" aria-hidden="true" tabindex="-1"></a>         <em>in-object</em> InObj2,</span>
<span id="cb6-223"><a href="#cb6-223" aria-hidden="true" tabindex="-1"></a>         <em>out-object</em> OutObj<span class="op">&gt;</span></span>
<span id="cb6-224"><a href="#cb6-224" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> add<span class="op">(</span>InObj1 x,</span>
<span id="cb6-225"><a href="#cb6-225" aria-hidden="true" tabindex="-1"></a>         InObj2 y,</span>
<span id="cb6-226"><a href="#cb6-226" aria-hidden="true" tabindex="-1"></a>         OutObj z<span class="op">)</span>;</span>
<span id="cb6-227"><a href="#cb6-227" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-228"><a href="#cb6-228" aria-hidden="true" tabindex="-1"></a>         <em>in-object</em> InObj1,</span>
<span id="cb6-229"><a href="#cb6-229" aria-hidden="true" tabindex="-1"></a>         <em>in-object</em> InObj2,</span>
<span id="cb6-230"><a href="#cb6-230" aria-hidden="true" tabindex="-1"></a>         <em>out-object</em> OutObj<span class="op">&gt;</span></span>
<span id="cb6-231"><a href="#cb6-231" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> add<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-232"><a href="#cb6-232" aria-hidden="true" tabindex="-1"></a>         InObj1 x,</span>
<span id="cb6-233"><a href="#cb6-233" aria-hidden="true" tabindex="-1"></a>         InObj2 y,</span>
<span id="cb6-234"><a href="#cb6-234" aria-hidden="true" tabindex="-1"></a>         OutObj z<span class="op">)</span>;</span>
<span id="cb6-235"><a href="#cb6-235" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-236"><a href="#cb6-236" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.dot],</span></span>
<span id="cb6-237"><a href="#cb6-237" aria-hidden="true" tabindex="-1"></a><span class="co">// dot product of two vectors</span></span>
<span id="cb6-238"><a href="#cb6-238" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-239"><a href="#cb6-239" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.dot.dotu],</span></span>
<span id="cb6-240"><a href="#cb6-240" aria-hidden="true" tabindex="-1"></a><span class="co">// nonconjugated dot product of two vectors</span></span>
<span id="cb6-241"><a href="#cb6-241" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb6-242"><a href="#cb6-242" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-243"><a href="#cb6-243" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-244"><a href="#cb6-244" aria-hidden="true" tabindex="-1"></a>T dot<span class="op">(</span>InVec1 v1,</span>
<span id="cb6-245"><a href="#cb6-245" aria-hidden="true" tabindex="-1"></a>      InVec2 v2,</span>
<span id="cb6-246"><a href="#cb6-246" aria-hidden="true" tabindex="-1"></a>      T init<span class="op">)</span>;</span>
<span id="cb6-247"><a href="#cb6-247" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-248"><a href="#cb6-248" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-249"><a href="#cb6-249" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-250"><a href="#cb6-250" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-251"><a href="#cb6-251" aria-hidden="true" tabindex="-1"></a>T dot<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-252"><a href="#cb6-252" aria-hidden="true" tabindex="-1"></a>      InVec1 v1,</span>
<span id="cb6-253"><a href="#cb6-253" aria-hidden="true" tabindex="-1"></a>      InVec2 v2,</span>
<span id="cb6-254"><a href="#cb6-254" aria-hidden="true" tabindex="-1"></a>      T init<span class="op">)</span>;</span>
<span id="cb6-255"><a href="#cb6-255" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb6-256"><a href="#cb6-256" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2<span class="op">&gt;</span></span>
<span id="cb6-257"><a href="#cb6-257" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dot<span class="op">(</span>InVec1 v1,</span>
<span id="cb6-258"><a href="#cb6-258" aria-hidden="true" tabindex="-1"></a>         InVec2 v2<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-259"><a href="#cb6-259" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-260"><a href="#cb6-260" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-261"><a href="#cb6-261" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2<span class="op">&gt;</span></span>
<span id="cb6-262"><a href="#cb6-262" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dot<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-263"><a href="#cb6-263" aria-hidden="true" tabindex="-1"></a>         InVec1 v1,</span>
<span id="cb6-264"><a href="#cb6-264" aria-hidden="true" tabindex="-1"></a>         InVec2 v2<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-265"><a href="#cb6-265" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-266"><a href="#cb6-266" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.dot.dotc],</span></span>
<span id="cb6-267"><a href="#cb6-267" aria-hidden="true" tabindex="-1"></a><span class="co">// conjugated dot product of two vectors</span></span>
<span id="cb6-268"><a href="#cb6-268" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb6-269"><a href="#cb6-269" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-270"><a href="#cb6-270" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-271"><a href="#cb6-271" aria-hidden="true" tabindex="-1"></a>T dotc<span class="op">(</span>InVec1 v1,</span>
<span id="cb6-272"><a href="#cb6-272" aria-hidden="true" tabindex="-1"></a>       InVec2 v2,</span>
<span id="cb6-273"><a href="#cb6-273" aria-hidden="true" tabindex="-1"></a>       T init<span class="op">)</span>;</span>
<span id="cb6-274"><a href="#cb6-274" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-275"><a href="#cb6-275" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-276"><a href="#cb6-276" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-277"><a href="#cb6-277" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-278"><a href="#cb6-278" aria-hidden="true" tabindex="-1"></a>T dotc<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-279"><a href="#cb6-279" aria-hidden="true" tabindex="-1"></a>       InVec1 v1,</span>
<span id="cb6-280"><a href="#cb6-280" aria-hidden="true" tabindex="-1"></a>       InVec2 v2,</span>
<span id="cb6-281"><a href="#cb6-281" aria-hidden="true" tabindex="-1"></a>       T init<span class="op">)</span>;</span>
<span id="cb6-282"><a href="#cb6-282" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb6-283"><a href="#cb6-283" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2<span class="op">&gt;</span></span>
<span id="cb6-284"><a href="#cb6-284" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dotc<span class="op">(</span>InVec1 v1,</span>
<span id="cb6-285"><a href="#cb6-285" aria-hidden="true" tabindex="-1"></a>          InVec2 v2<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-286"><a href="#cb6-286" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-287"><a href="#cb6-287" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-288"><a href="#cb6-288" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2<span class="op">&gt;</span></span>
<span id="cb6-289"><a href="#cb6-289" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dotc<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-290"><a href="#cb6-290" aria-hidden="true" tabindex="-1"></a>          InVec1 v1,</span>
<span id="cb6-291"><a href="#cb6-291" aria-hidden="true" tabindex="-1"></a>          InVec2 v2<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-292"><a href="#cb6-292" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-293"><a href="#cb6-293" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.ssq],</span></span>
<span id="cb6-294"><a href="#cb6-294" aria-hidden="true" tabindex="-1"></a><span class="co">// Scaled sum of squares of a vector&#39;s elements</span></span>
<span id="cb6-295"><a href="#cb6-295" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-296"><a href="#cb6-296" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> sum_of_squares_result <span class="op">{</span></span>
<span id="cb6-297"><a href="#cb6-297" aria-hidden="true" tabindex="-1"></a>  T scaling_factor;</span>
<span id="cb6-298"><a href="#cb6-298" aria-hidden="true" tabindex="-1"></a>  T scaled_sum_of_squares;</span>
<span id="cb6-299"><a href="#cb6-299" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb6-300"><a href="#cb6-300" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec,</span>
<span id="cb6-301"><a href="#cb6-301" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-302"><a href="#cb6-302" aria-hidden="true" tabindex="-1"></a>sum_of_squares_result<span class="op">&lt;</span>T<span class="op">&gt;</span> vector_sum_of_squares<span class="op">(</span></span>
<span id="cb6-303"><a href="#cb6-303" aria-hidden="true" tabindex="-1"></a>  InVec v,</span>
<span id="cb6-304"><a href="#cb6-304" aria-hidden="true" tabindex="-1"></a>  sum_of_squares_result<span class="op">&lt;</span>T<span class="op">&gt;</span> init<span class="op">)</span>;</span>
<span id="cb6-305"><a href="#cb6-305" aria-hidden="true" tabindex="-1"></a>sum_of_squares_result<span class="op">&lt;</span>T<span class="op">&gt;</span> vector_sum_of_squares<span class="op">(</span></span>
<span id="cb6-306"><a href="#cb6-306" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-307"><a href="#cb6-307" aria-hidden="true" tabindex="-1"></a>  InVec v,</span>
<span id="cb6-308"><a href="#cb6-308" aria-hidden="true" tabindex="-1"></a>  sum_of_squares_result<span class="op">&lt;</span>T<span class="op">&gt;</span> init<span class="op">)</span>;</span>
<span id="cb6-309"><a href="#cb6-309" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-310"><a href="#cb6-310" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.nrm2],</span></span>
<span id="cb6-311"><a href="#cb6-311" aria-hidden="true" tabindex="-1"></a><span class="co">// Euclidean norm of a vector</span></span>
<span id="cb6-312"><a href="#cb6-312" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec,</span>
<span id="cb6-313"><a href="#cb6-313" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-314"><a href="#cb6-314" aria-hidden="true" tabindex="-1"></a>T vector_norm2<span class="op">(</span>InVec v,</span>
<span id="cb6-315"><a href="#cb6-315" aria-hidden="true" tabindex="-1"></a>               T init<span class="op">)</span>;</span>
<span id="cb6-316"><a href="#cb6-316" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-317"><a href="#cb6-317" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-318"><a href="#cb6-318" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-319"><a href="#cb6-319" aria-hidden="true" tabindex="-1"></a>T vector_norm2<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-320"><a href="#cb6-320" aria-hidden="true" tabindex="-1"></a>               InVec v,</span>
<span id="cb6-321"><a href="#cb6-321" aria-hidden="true" tabindex="-1"></a>               T init<span class="op">)</span>;</span>
<span id="cb6-322"><a href="#cb6-322" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec<span class="op">&gt;</span></span>
<span id="cb6-323"><a href="#cb6-323" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> vector_norm2<span class="op">(</span>InVec v<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-324"><a href="#cb6-324" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-325"><a href="#cb6-325" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec<span class="op">&gt;</span></span>
<span id="cb6-326"><a href="#cb6-326" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> vector_norm2<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-327"><a href="#cb6-327" aria-hidden="true" tabindex="-1"></a>                  InVec v<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-328"><a href="#cb6-328" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-329"><a href="#cb6-329" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.asum],</span></span>
<span id="cb6-330"><a href="#cb6-330" aria-hidden="true" tabindex="-1"></a><span class="co">// sum of absolute values of vector elements</span></span>
<span id="cb6-331"><a href="#cb6-331" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec,</span>
<span id="cb6-332"><a href="#cb6-332" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-333"><a href="#cb6-333" aria-hidden="true" tabindex="-1"></a>T vector_abs_sum<span class="op">(</span>InVec v,</span>
<span id="cb6-334"><a href="#cb6-334" aria-hidden="true" tabindex="-1"></a>                 T init<span class="op">)</span>;</span>
<span id="cb6-335"><a href="#cb6-335" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-336"><a href="#cb6-336" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-337"><a href="#cb6-337" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-338"><a href="#cb6-338" aria-hidden="true" tabindex="-1"></a>T vector_abs_sum<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-339"><a href="#cb6-339" aria-hidden="true" tabindex="-1"></a>                 InVec v,</span>
<span id="cb6-340"><a href="#cb6-340" aria-hidden="true" tabindex="-1"></a>                 T init<span class="op">)</span>;</span>
<span id="cb6-341"><a href="#cb6-341" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec<span class="op">&gt;</span></span>
<span id="cb6-342"><a href="#cb6-342" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> vector_abs_sum<span class="op">(</span>InVec v<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-343"><a href="#cb6-343" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-344"><a href="#cb6-344" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec<span class="op">&gt;</span></span>
<span id="cb6-345"><a href="#cb6-345" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> vector_abs_sum<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-346"><a href="#cb6-346" aria-hidden="true" tabindex="-1"></a>                    InVec v<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-347"><a href="#cb6-347" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-348"><a href="#cb6-348" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.iamax],</span></span>
<span id="cb6-349"><a href="#cb6-349" aria-hidden="true" tabindex="-1"></a><span class="co">// index of maximum absolute value of vector elements</span></span>
<span id="cb6-350"><a href="#cb6-350" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec<span class="op">&gt;</span></span>
<span id="cb6-351"><a href="#cb6-351" aria-hidden="true" tabindex="-1"></a><span class="kw">typename</span> InVec<span class="op">::</span>extents_type idx_abs_max<span class="op">(</span>InVec v<span class="op">)</span>;</span>
<span id="cb6-352"><a href="#cb6-352" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-353"><a href="#cb6-353" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec<span class="op">&gt;</span></span>
<span id="cb6-354"><a href="#cb6-354" aria-hidden="true" tabindex="-1"></a><span class="kw">typename</span> InVec<span class="op">::</span>extents_type idx_abs_max<span class="op">(</span></span>
<span id="cb6-355"><a href="#cb6-355" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-356"><a href="#cb6-356" aria-hidden="true" tabindex="-1"></a>  InVec v<span class="op">)</span>;</span>
<span id="cb6-357"><a href="#cb6-357" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-358"><a href="#cb6-358" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.matfrobnorm],</span></span>
<span id="cb6-359"><a href="#cb6-359" aria-hidden="true" tabindex="-1"></a><span class="co">// Frobenius norm of a matrix</span></span>
<span id="cb6-360"><a href="#cb6-360" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-361"><a href="#cb6-361" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-362"><a href="#cb6-362" aria-hidden="true" tabindex="-1"></a>T matrix_frob_norm<span class="op">(</span></span>
<span id="cb6-363"><a href="#cb6-363" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-364"><a href="#cb6-364" aria-hidden="true" tabindex="-1"></a>  T init<span class="op">)</span>;</span>
<span id="cb6-365"><a href="#cb6-365" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-366"><a href="#cb6-366" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-367"><a href="#cb6-367" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-368"><a href="#cb6-368" aria-hidden="true" tabindex="-1"></a>T matrix_frob_norm<span class="op">(</span></span>
<span id="cb6-369"><a href="#cb6-369" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-370"><a href="#cb6-370" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-371"><a href="#cb6-371" aria-hidden="true" tabindex="-1"></a>  T init<span class="op">)</span>;</span>
<span id="cb6-372"><a href="#cb6-372" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat<span class="op">&gt;</span></span>
<span id="cb6-373"><a href="#cb6-373" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> matrix_frob_norm<span class="op">(</span></span>
<span id="cb6-374"><a href="#cb6-374" aria-hidden="true" tabindex="-1"></a>  InMat A<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-375"><a href="#cb6-375" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-376"><a href="#cb6-376" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat<span class="op">&gt;</span></span>
<span id="cb6-377"><a href="#cb6-377" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> matrix_frob_norm<span class="op">(</span></span>
<span id="cb6-378"><a href="#cb6-378" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-379"><a href="#cb6-379" aria-hidden="true" tabindex="-1"></a>  InMat A<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-380"><a href="#cb6-380" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-381"><a href="#cb6-381" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.matonenorm],</span></span>
<span id="cb6-382"><a href="#cb6-382" aria-hidden="true" tabindex="-1"></a><span class="co">// One norm of a matrix</span></span>
<span id="cb6-383"><a href="#cb6-383" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-384"><a href="#cb6-384" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-385"><a href="#cb6-385" aria-hidden="true" tabindex="-1"></a>T matrix_one_norm<span class="op">(</span></span>
<span id="cb6-386"><a href="#cb6-386" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-387"><a href="#cb6-387" aria-hidden="true" tabindex="-1"></a>  T init<span class="op">)</span>;</span>
<span id="cb6-388"><a href="#cb6-388" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-389"><a href="#cb6-389" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-390"><a href="#cb6-390" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-391"><a href="#cb6-391" aria-hidden="true" tabindex="-1"></a>T matrix_one_norm<span class="op">(</span></span>
<span id="cb6-392"><a href="#cb6-392" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-393"><a href="#cb6-393" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-394"><a href="#cb6-394" aria-hidden="true" tabindex="-1"></a>  T init<span class="op">)</span>;</span>
<span id="cb6-395"><a href="#cb6-395" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat<span class="op">&gt;</span></span>
<span id="cb6-396"><a href="#cb6-396" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> matrix_one_norm<span class="op">(</span></span>
<span id="cb6-397"><a href="#cb6-397" aria-hidden="true" tabindex="-1"></a>  InMat A<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-398"><a href="#cb6-398" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-399"><a href="#cb6-399" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat<span class="op">&gt;</span></span>
<span id="cb6-400"><a href="#cb6-400" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> matrix_one_norm<span class="op">(</span></span>
<span id="cb6-401"><a href="#cb6-401" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-402"><a href="#cb6-402" aria-hidden="true" tabindex="-1"></a>  InMat A<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-403"><a href="#cb6-403" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-404"><a href="#cb6-404" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas1.matinfnorm],</span></span>
<span id="cb6-405"><a href="#cb6-405" aria-hidden="true" tabindex="-1"></a><span class="co">// Infinity norm of a matrix</span></span>
<span id="cb6-406"><a href="#cb6-406" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-407"><a href="#cb6-407" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-408"><a href="#cb6-408" aria-hidden="true" tabindex="-1"></a>T matrix_inf_norm<span class="op">(</span></span>
<span id="cb6-409"><a href="#cb6-409" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-410"><a href="#cb6-410" aria-hidden="true" tabindex="-1"></a>  T init<span class="op">)</span>;</span>
<span id="cb6-411"><a href="#cb6-411" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-412"><a href="#cb6-412" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-413"><a href="#cb6-413" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-414"><a href="#cb6-414" aria-hidden="true" tabindex="-1"></a>T matrix_inf_norm<span class="op">(</span></span>
<span id="cb6-415"><a href="#cb6-415" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-416"><a href="#cb6-416" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-417"><a href="#cb6-417" aria-hidden="true" tabindex="-1"></a>  T init<span class="op">)</span>;</span>
<span id="cb6-418"><a href="#cb6-418" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat<span class="op">&gt;</span></span>
<span id="cb6-419"><a href="#cb6-419" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> matrix_inf_norm<span class="op">(</span></span>
<span id="cb6-420"><a href="#cb6-420" aria-hidden="true" tabindex="-1"></a>  InMat A<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-421"><a href="#cb6-421" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-422"><a href="#cb6-422" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat<span class="op">&gt;</span></span>
<span id="cb6-423"><a href="#cb6-423" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> matrix_inf_norm<span class="op">(</span></span>
<span id="cb6-424"><a href="#cb6-424" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-425"><a href="#cb6-425" aria-hidden="true" tabindex="-1"></a>  InMat A<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb6-426"><a href="#cb6-426" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-427"><a href="#cb6-427" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.gemv],</span></span>
<span id="cb6-428"><a href="#cb6-428" aria-hidden="true" tabindex="-1"></a><span class="co">// general matrix-vector product</span></span>
<span id="cb6-429"><a href="#cb6-429" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-430"><a href="#cb6-430" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-431"><a href="#cb6-431" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-432"><a href="#cb6-432" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_vector_product<span class="op">(</span>InMat A,</span>
<span id="cb6-433"><a href="#cb6-433" aria-hidden="true" tabindex="-1"></a>                           InVec x,</span>
<span id="cb6-434"><a href="#cb6-434" aria-hidden="true" tabindex="-1"></a>                           OutVec y<span class="op">)</span>;</span>
<span id="cb6-435"><a href="#cb6-435" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-436"><a href="#cb6-436" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-437"><a href="#cb6-437" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-438"><a href="#cb6-438" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-439"><a href="#cb6-439" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_vector_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-440"><a href="#cb6-440" aria-hidden="true" tabindex="-1"></a>                           InMat A,</span>
<span id="cb6-441"><a href="#cb6-441" aria-hidden="true" tabindex="-1"></a>                           InVec x,</span>
<span id="cb6-442"><a href="#cb6-442" aria-hidden="true" tabindex="-1"></a>                           OutVec y<span class="op">)</span>;</span>
<span id="cb6-443"><a href="#cb6-443" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-444"><a href="#cb6-444" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-445"><a href="#cb6-445" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-446"><a href="#cb6-446" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-447"><a href="#cb6-447" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_vector_product<span class="op">(</span>InMat A,</span>
<span id="cb6-448"><a href="#cb6-448" aria-hidden="true" tabindex="-1"></a>                           InVec1 x,</span>
<span id="cb6-449"><a href="#cb6-449" aria-hidden="true" tabindex="-1"></a>                           InVec2 y,</span>
<span id="cb6-450"><a href="#cb6-450" aria-hidden="true" tabindex="-1"></a>                           OutVec z<span class="op">)</span>;</span>
<span id="cb6-451"><a href="#cb6-451" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-452"><a href="#cb6-452" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-453"><a href="#cb6-453" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-454"><a href="#cb6-454" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-455"><a href="#cb6-455" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-456"><a href="#cb6-456" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_vector_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-457"><a href="#cb6-457" aria-hidden="true" tabindex="-1"></a>                           InMat A,</span>
<span id="cb6-458"><a href="#cb6-458" aria-hidden="true" tabindex="-1"></a>                           InVec1 x,</span>
<span id="cb6-459"><a href="#cb6-459" aria-hidden="true" tabindex="-1"></a>                           InVec2 y,</span>
<span id="cb6-460"><a href="#cb6-460" aria-hidden="true" tabindex="-1"></a>                           OutVec z<span class="op">)</span>;</span>
<span id="cb6-461"><a href="#cb6-461" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-462"><a href="#cb6-462" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.symv],</span></span>
<span id="cb6-463"><a href="#cb6-463" aria-hidden="true" tabindex="-1"></a><span class="co">// symmetric matrix-vector product</span></span>
<span id="cb6-464"><a href="#cb6-464" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-465"><a href="#cb6-465" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-466"><a href="#cb6-466" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-467"><a href="#cb6-467" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-468"><a href="#cb6-468" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_vector_product<span class="op">(</span>InMat A,</span>
<span id="cb6-469"><a href="#cb6-469" aria-hidden="true" tabindex="-1"></a>                                     Triangle t,</span>
<span id="cb6-470"><a href="#cb6-470" aria-hidden="true" tabindex="-1"></a>                                     InVec x,</span>
<span id="cb6-471"><a href="#cb6-471" aria-hidden="true" tabindex="-1"></a>                                     OutVec y<span class="op">)</span>;</span>
<span id="cb6-472"><a href="#cb6-472" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-473"><a href="#cb6-473" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-474"><a href="#cb6-474" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-475"><a href="#cb6-475" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-476"><a href="#cb6-476" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-477"><a href="#cb6-477" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_vector_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-478"><a href="#cb6-478" aria-hidden="true" tabindex="-1"></a>                                     InMat A,</span>
<span id="cb6-479"><a href="#cb6-479" aria-hidden="true" tabindex="-1"></a>                                     Triangle t,</span>
<span id="cb6-480"><a href="#cb6-480" aria-hidden="true" tabindex="-1"></a>                                     InVec x,</span>
<span id="cb6-481"><a href="#cb6-481" aria-hidden="true" tabindex="-1"></a>                                     OutVec y<span class="op">)</span>;</span>
<span id="cb6-482"><a href="#cb6-482" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-483"><a href="#cb6-483" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-484"><a href="#cb6-484" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-485"><a href="#cb6-485" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-486"><a href="#cb6-486" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-487"><a href="#cb6-487" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_vector_product<span class="op">(</span></span>
<span id="cb6-488"><a href="#cb6-488" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-489"><a href="#cb6-489" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-490"><a href="#cb6-490" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb6-491"><a href="#cb6-491" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb6-492"><a href="#cb6-492" aria-hidden="true" tabindex="-1"></a>  OutVec z<span class="op">)</span>;</span>
<span id="cb6-493"><a href="#cb6-493" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-494"><a href="#cb6-494" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-495"><a href="#cb6-495" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-496"><a href="#cb6-496" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-497"><a href="#cb6-497" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-498"><a href="#cb6-498" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-499"><a href="#cb6-499" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-500"><a href="#cb6-500" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_vector_product<span class="op">(</span></span>
<span id="cb6-501"><a href="#cb6-501" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-502"><a href="#cb6-502" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-503"><a href="#cb6-503" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-504"><a href="#cb6-504" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb6-505"><a href="#cb6-505" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb6-506"><a href="#cb6-506" aria-hidden="true" tabindex="-1"></a>  OutVec z<span class="op">)</span>;</span>
<span id="cb6-507"><a href="#cb6-507" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-508"><a href="#cb6-508" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.hemv],</span></span>
<span id="cb6-509"><a href="#cb6-509" aria-hidden="true" tabindex="-1"></a><span class="co">// Hermitian matrix-vector product</span></span>
<span id="cb6-510"><a href="#cb6-510" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-511"><a href="#cb6-511" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-512"><a href="#cb6-512" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-513"><a href="#cb6-513" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-514"><a href="#cb6-514" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_vector_product<span class="op">(</span>InMat A,</span>
<span id="cb6-515"><a href="#cb6-515" aria-hidden="true" tabindex="-1"></a>                                     Triangle t,</span>
<span id="cb6-516"><a href="#cb6-516" aria-hidden="true" tabindex="-1"></a>                                     InVec x,</span>
<span id="cb6-517"><a href="#cb6-517" aria-hidden="true" tabindex="-1"></a>                                     OutVec y<span class="op">)</span>;</span>
<span id="cb6-518"><a href="#cb6-518" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-519"><a href="#cb6-519" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-520"><a href="#cb6-520" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-521"><a href="#cb6-521" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-522"><a href="#cb6-522" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-523"><a href="#cb6-523" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_vector_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-524"><a href="#cb6-524" aria-hidden="true" tabindex="-1"></a>                                     InMat A,</span>
<span id="cb6-525"><a href="#cb6-525" aria-hidden="true" tabindex="-1"></a>                                     Triangle t,</span>
<span id="cb6-526"><a href="#cb6-526" aria-hidden="true" tabindex="-1"></a>                                     InVec x,</span>
<span id="cb6-527"><a href="#cb6-527" aria-hidden="true" tabindex="-1"></a>                                     OutVec y<span class="op">)</span>;</span>
<span id="cb6-528"><a href="#cb6-528" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-529"><a href="#cb6-529" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-530"><a href="#cb6-530" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-531"><a href="#cb6-531" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-532"><a href="#cb6-532" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-533"><a href="#cb6-533" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_vector_product<span class="op">(</span>InMat A,</span>
<span id="cb6-534"><a href="#cb6-534" aria-hidden="true" tabindex="-1"></a>                                     Triangle t,</span>
<span id="cb6-535"><a href="#cb6-535" aria-hidden="true" tabindex="-1"></a>                                     InVec1 x,</span>
<span id="cb6-536"><a href="#cb6-536" aria-hidden="true" tabindex="-1"></a>                                     InVec2 y,</span>
<span id="cb6-537"><a href="#cb6-537" aria-hidden="true" tabindex="-1"></a>                                     OutVec z<span class="op">)</span>;</span>
<span id="cb6-538"><a href="#cb6-538" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-539"><a href="#cb6-539" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-540"><a href="#cb6-540" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-541"><a href="#cb6-541" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-542"><a href="#cb6-542" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-543"><a href="#cb6-543" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-544"><a href="#cb6-544" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-545"><a href="#cb6-545" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_vector_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-546"><a href="#cb6-546" aria-hidden="true" tabindex="-1"></a>                                     InMat A,</span>
<span id="cb6-547"><a href="#cb6-547" aria-hidden="true" tabindex="-1"></a>                                     Triangle t,</span>
<span id="cb6-548"><a href="#cb6-548" aria-hidden="true" tabindex="-1"></a>                                     InVec1 x,</span>
<span id="cb6-549"><a href="#cb6-549" aria-hidden="true" tabindex="-1"></a>                                     InVec2 y,</span>
<span id="cb6-550"><a href="#cb6-550" aria-hidden="true" tabindex="-1"></a>                                     OutVec z<span class="op">)</span>;</span>
<span id="cb6-551"><a href="#cb6-551" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-552"><a href="#cb6-552" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.trmv],</span></span>
<span id="cb6-553"><a href="#cb6-553" aria-hidden="true" tabindex="-1"></a><span class="co">// Triangular matrix-vector product</span></span>
<span id="cb6-554"><a href="#cb6-554" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-555"><a href="#cb6-555" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.trmv.ov],</span></span>
<span id="cb6-556"><a href="#cb6-556" aria-hidden="true" tabindex="-1"></a><span class="co">// Overwriting triangular matrix-vector product</span></span>
<span id="cb6-557"><a href="#cb6-557" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-558"><a href="#cb6-558" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-559"><a href="#cb6-559" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-560"><a href="#cb6-560" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-561"><a href="#cb6-561" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-562"><a href="#cb6-562" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_product<span class="op">(</span></span>
<span id="cb6-563"><a href="#cb6-563" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-564"><a href="#cb6-564" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-565"><a href="#cb6-565" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-566"><a href="#cb6-566" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb6-567"><a href="#cb6-567" aria-hidden="true" tabindex="-1"></a>  OutVec y<span class="op">)</span>;</span>
<span id="cb6-568"><a href="#cb6-568" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-569"><a href="#cb6-569" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-570"><a href="#cb6-570" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-571"><a href="#cb6-571" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-572"><a href="#cb6-572" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-573"><a href="#cb6-573" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-574"><a href="#cb6-574" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_product<span class="op">(</span></span>
<span id="cb6-575"><a href="#cb6-575" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-576"><a href="#cb6-576" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-577"><a href="#cb6-577" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-578"><a href="#cb6-578" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-579"><a href="#cb6-579" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb6-580"><a href="#cb6-580" aria-hidden="true" tabindex="-1"></a>  OutVec y<span class="op">)</span>;</span>
<span id="cb6-581"><a href="#cb6-581" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-582"><a href="#cb6-582" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.trmv.in-place],</span></span>
<span id="cb6-583"><a href="#cb6-583" aria-hidden="true" tabindex="-1"></a><span class="co">// In-place triangular matrix-vector product</span></span>
<span id="cb6-584"><a href="#cb6-584" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-585"><a href="#cb6-585" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-586"><a href="#cb6-586" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-587"><a href="#cb6-587" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec<span class="op">&gt;</span></span>
<span id="cb6-588"><a href="#cb6-588" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_product<span class="op">(</span></span>
<span id="cb6-589"><a href="#cb6-589" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-590"><a href="#cb6-590" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-591"><a href="#cb6-591" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-592"><a href="#cb6-592" aria-hidden="true" tabindex="-1"></a>  InOutVec y<span class="op">)</span>;</span>
<span id="cb6-593"><a href="#cb6-593" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-594"><a href="#cb6-594" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-595"><a href="#cb6-595" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-596"><a href="#cb6-596" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-597"><a href="#cb6-597" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec<span class="op">&gt;</span></span>
<span id="cb6-598"><a href="#cb6-598" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_product<span class="op">(</span></span>
<span id="cb6-599"><a href="#cb6-599" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-600"><a href="#cb6-600" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-601"><a href="#cb6-601" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-602"><a href="#cb6-602" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-603"><a href="#cb6-603" aria-hidden="true" tabindex="-1"></a>  InOutVec y<span class="op">)</span>;</span>
<span id="cb6-604"><a href="#cb6-604" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-605"><a href="#cb6-605" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.trmv.up],</span></span>
<span id="cb6-606"><a href="#cb6-606" aria-hidden="true" tabindex="-1"></a><span class="co">// Updating triangular matrix-vector product</span></span>
<span id="cb6-607"><a href="#cb6-607" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-608"><a href="#cb6-608" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-609"><a href="#cb6-609" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-610"><a href="#cb6-610" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-611"><a href="#cb6-611" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-612"><a href="#cb6-612" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-613"><a href="#cb6-613" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_product<span class="op">(</span>InMat A,</span>
<span id="cb6-614"><a href="#cb6-614" aria-hidden="true" tabindex="-1"></a>                                      Triangle t,</span>
<span id="cb6-615"><a href="#cb6-615" aria-hidden="true" tabindex="-1"></a>                                      DiagonalStorage d,</span>
<span id="cb6-616"><a href="#cb6-616" aria-hidden="true" tabindex="-1"></a>                                      InVec1 x,</span>
<span id="cb6-617"><a href="#cb6-617" aria-hidden="true" tabindex="-1"></a>                                      InVec2 y,</span>
<span id="cb6-618"><a href="#cb6-618" aria-hidden="true" tabindex="-1"></a>                                      OutVec z<span class="op">)</span>;</span>
<span id="cb6-619"><a href="#cb6-619" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-620"><a href="#cb6-620" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-621"><a href="#cb6-621" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-622"><a href="#cb6-622" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-623"><a href="#cb6-623" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-624"><a href="#cb6-624" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-625"><a href="#cb6-625" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-626"><a href="#cb6-626" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-627"><a href="#cb6-627" aria-hidden="true" tabindex="-1"></a>                                      InMat A,</span>
<span id="cb6-628"><a href="#cb6-628" aria-hidden="true" tabindex="-1"></a>                                      Triangle t,</span>
<span id="cb6-629"><a href="#cb6-629" aria-hidden="true" tabindex="-1"></a>                                      DiagonalStorage d,</span>
<span id="cb6-630"><a href="#cb6-630" aria-hidden="true" tabindex="-1"></a>                                      InVec1 x,</span>
<span id="cb6-631"><a href="#cb6-631" aria-hidden="true" tabindex="-1"></a>                                      InVec2 y,</span>
<span id="cb6-632"><a href="#cb6-632" aria-hidden="true" tabindex="-1"></a>                                      OutVec z<span class="op">)</span>;</span>
<span id="cb6-633"><a href="#cb6-633" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-634"><a href="#cb6-634" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.trsv],</span></span>
<span id="cb6-635"><a href="#cb6-635" aria-hidden="true" tabindex="-1"></a><span class="co">// Solve a triangular linear system</span></span>
<span id="cb6-636"><a href="#cb6-636" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-637"><a href="#cb6-637" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.trsv.not-in-place],</span></span>
<span id="cb6-638"><a href="#cb6-638" aria-hidden="true" tabindex="-1"></a><span class="co">// Solve a triangular linear system, not in place</span></span>
<span id="cb6-639"><a href="#cb6-639" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-640"><a href="#cb6-640" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-641"><a href="#cb6-641" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-642"><a href="#cb6-642" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-643"><a href="#cb6-643" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec,</span>
<span id="cb6-644"><a href="#cb6-644" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb6-645"><a href="#cb6-645" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb6-646"><a href="#cb6-646" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-647"><a href="#cb6-647" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-648"><a href="#cb6-648" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-649"><a href="#cb6-649" aria-hidden="true" tabindex="-1"></a>  InVec b,</span>
<span id="cb6-650"><a href="#cb6-650" aria-hidden="true" tabindex="-1"></a>  OutVec x,</span>
<span id="cb6-651"><a href="#cb6-651" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb6-652"><a href="#cb6-652" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-653"><a href="#cb6-653" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-654"><a href="#cb6-654" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-655"><a href="#cb6-655" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-656"><a href="#cb6-656" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-657"><a href="#cb6-657" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec,</span>
<span id="cb6-658"><a href="#cb6-658" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb6-659"><a href="#cb6-659" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb6-660"><a href="#cb6-660" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-661"><a href="#cb6-661" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-662"><a href="#cb6-662" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-663"><a href="#cb6-663" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-664"><a href="#cb6-664" aria-hidden="true" tabindex="-1"></a>  InVec b,</span>
<span id="cb6-665"><a href="#cb6-665" aria-hidden="true" tabindex="-1"></a>  OutVec x,</span>
<span id="cb6-666"><a href="#cb6-666" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb6-667"><a href="#cb6-667" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-668"><a href="#cb6-668" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-669"><a href="#cb6-669" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-670"><a href="#cb6-670" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-671"><a href="#cb6-671" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-672"><a href="#cb6-672" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb6-673"><a href="#cb6-673" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-674"><a href="#cb6-674" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-675"><a href="#cb6-675" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-676"><a href="#cb6-676" aria-hidden="true" tabindex="-1"></a>  InVec b,</span>
<span id="cb6-677"><a href="#cb6-677" aria-hidden="true" tabindex="-1"></a>  OutVec x<span class="op">)</span>;</span>
<span id="cb6-678"><a href="#cb6-678" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-679"><a href="#cb6-679" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-680"><a href="#cb6-680" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-681"><a href="#cb6-681" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-682"><a href="#cb6-682" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-683"><a href="#cb6-683" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb6-684"><a href="#cb6-684" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb6-685"><a href="#cb6-685" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-686"><a href="#cb6-686" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-687"><a href="#cb6-687" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-688"><a href="#cb6-688" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-689"><a href="#cb6-689" aria-hidden="true" tabindex="-1"></a>  InVec b,</span>
<span id="cb6-690"><a href="#cb6-690" aria-hidden="true" tabindex="-1"></a>  OutVec x<span class="op">)</span>;</span>
<span id="cb6-691"><a href="#cb6-691" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-692"><a href="#cb6-692" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.trsv.in-place],</span></span>
<span id="cb6-693"><a href="#cb6-693" aria-hidden="true" tabindex="-1"></a><span class="co">// Solve a triangular linear system, in place</span></span>
<span id="cb6-694"><a href="#cb6-694" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-695"><a href="#cb6-695" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-696"><a href="#cb6-696" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-697"><a href="#cb6-697" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec,</span>
<span id="cb6-698"><a href="#cb6-698" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb6-699"><a href="#cb6-699" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb6-700"><a href="#cb6-700" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-701"><a href="#cb6-701" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-702"><a href="#cb6-702" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-703"><a href="#cb6-703" aria-hidden="true" tabindex="-1"></a>  InOutVec b,</span>
<span id="cb6-704"><a href="#cb6-704" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb6-705"><a href="#cb6-705" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-706"><a href="#cb6-706" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-707"><a href="#cb6-707" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-708"><a href="#cb6-708" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-709"><a href="#cb6-709" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec,</span>
<span id="cb6-710"><a href="#cb6-710" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb6-711"><a href="#cb6-711" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb6-712"><a href="#cb6-712" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-713"><a href="#cb6-713" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-714"><a href="#cb6-714" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-715"><a href="#cb6-715" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-716"><a href="#cb6-716" aria-hidden="true" tabindex="-1"></a>  InOutVec b,</span>
<span id="cb6-717"><a href="#cb6-717" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb6-718"><a href="#cb6-718" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb6-719"><a href="#cb6-719" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-720"><a href="#cb6-720" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-721"><a href="#cb6-721" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec<span class="op">&gt;</span></span>
<span id="cb6-722"><a href="#cb6-722" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb6-723"><a href="#cb6-723" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-724"><a href="#cb6-724" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-725"><a href="#cb6-725" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-726"><a href="#cb6-726" aria-hidden="true" tabindex="-1"></a>  InOutVec b<span class="op">)</span>;</span>
<span id="cb6-727"><a href="#cb6-727" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-728"><a href="#cb6-728" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb6-729"><a href="#cb6-729" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-730"><a href="#cb6-730" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-731"><a href="#cb6-731" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec<span class="op">&gt;</span></span>
<span id="cb6-732"><a href="#cb6-732" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb6-733"><a href="#cb6-733" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-734"><a href="#cb6-734" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-735"><a href="#cb6-735" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-736"><a href="#cb6-736" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-737"><a href="#cb6-737" aria-hidden="true" tabindex="-1"></a>  InOutVec b<span class="op">)</span>;</span>
<span id="cb6-738"><a href="#cb6-738" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-739"><a href="#cb6-739" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.rank1.geru],</span></span>
<span id="cb6-740"><a href="#cb6-740" aria-hidden="true" tabindex="-1"></a><span class="co">// nonconjugated rank-1 matrix update</span></span>
<span id="cb6-741"><a href="#cb6-741" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb6-742"><a href="#cb6-742" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-743"><a href="#cb6-743" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb6-744"><a href="#cb6-744" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_rank_1_update<span class="op">(</span></span>
<span id="cb6-745"><a href="#cb6-745" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb6-746"><a href="#cb6-746" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb6-747"><a href="#cb6-747" aria-hidden="true" tabindex="-1"></a>  InOutMat A<span class="op">)</span>;</span>
<span id="cb6-748"><a href="#cb6-748" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-749"><a href="#cb6-749" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-750"><a href="#cb6-750" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-751"><a href="#cb6-751" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb6-752"><a href="#cb6-752" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_rank_1_update<span class="op">(</span></span>
<span id="cb6-753"><a href="#cb6-753" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-754"><a href="#cb6-754" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb6-755"><a href="#cb6-755" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb6-756"><a href="#cb6-756" aria-hidden="true" tabindex="-1"></a>  InOutMat A<span class="op">)</span>;</span>
<span id="cb6-757"><a href="#cb6-757" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-758"><a href="#cb6-758" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.rank1.gerc],</span></span>
<span id="cb6-759"><a href="#cb6-759" aria-hidden="true" tabindex="-1"></a><span class="co">// conjugated rank-1 matrix update</span></span>
<span id="cb6-760"><a href="#cb6-760" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb6-761"><a href="#cb6-761" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-762"><a href="#cb6-762" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb6-763"><a href="#cb6-763" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_rank_1_update_c<span class="op">(</span></span>
<span id="cb6-764"><a href="#cb6-764" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb6-765"><a href="#cb6-765" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb6-766"><a href="#cb6-766" aria-hidden="true" tabindex="-1"></a>  InOutMat A<span class="op">)</span>;</span>
<span id="cb6-767"><a href="#cb6-767" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-768"><a href="#cb6-768" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-769"><a href="#cb6-769" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-770"><a href="#cb6-770" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb6-771"><a href="#cb6-771" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_rank_1_update_c<span class="op">(</span></span>
<span id="cb6-772"><a href="#cb6-772" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-773"><a href="#cb6-773" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb6-774"><a href="#cb6-774" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb6-775"><a href="#cb6-775" aria-hidden="true" tabindex="-1"></a>  InOutMat A<span class="op">)</span>;</span>
<span id="cb6-776"><a href="#cb6-776" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-777"><a href="#cb6-777" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.rank1.syr],</span></span>
<span id="cb6-778"><a href="#cb6-778" aria-hidden="true" tabindex="-1"></a><span class="co">// symmetric rank-1 matrix update</span></span>
<span id="cb6-779"><a href="#cb6-779" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec,</span>
<span id="cb6-780"><a href="#cb6-780" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-781"><a href="#cb6-781" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-782"><a href="#cb6-782" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb6-783"><a href="#cb6-783" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb6-784"><a href="#cb6-784" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb6-785"><a href="#cb6-785" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-786"><a href="#cb6-786" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-787"><a href="#cb6-787" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-788"><a href="#cb6-788" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-789"><a href="#cb6-789" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-790"><a href="#cb6-790" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb6-791"><a href="#cb6-791" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-792"><a href="#cb6-792" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb6-793"><a href="#cb6-793" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb6-794"><a href="#cb6-794" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-795"><a href="#cb6-795" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T,</span>
<span id="cb6-796"><a href="#cb6-796" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-797"><a href="#cb6-797" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-798"><a href="#cb6-798" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-799"><a href="#cb6-799" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb6-800"><a href="#cb6-800" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb6-801"><a href="#cb6-801" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb6-802"><a href="#cb6-802" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb6-803"><a href="#cb6-803" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-804"><a href="#cb6-804" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-805"><a href="#cb6-805" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T,</span>
<span id="cb6-806"><a href="#cb6-806" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-807"><a href="#cb6-807" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-808"><a href="#cb6-808" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-809"><a href="#cb6-809" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb6-810"><a href="#cb6-810" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-811"><a href="#cb6-811" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb6-812"><a href="#cb6-812" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb6-813"><a href="#cb6-813" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb6-814"><a href="#cb6-814" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-815"><a href="#cb6-815" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-816"><a href="#cb6-816" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.rank1.her],</span></span>
<span id="cb6-817"><a href="#cb6-817" aria-hidden="true" tabindex="-1"></a><span class="co">// Hermitian rank-1 matrix update</span></span>
<span id="cb6-818"><a href="#cb6-818" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec,</span>
<span id="cb6-819"><a href="#cb6-819" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-820"><a href="#cb6-820" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-821"><a href="#cb6-821" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb6-822"><a href="#cb6-822" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb6-823"><a href="#cb6-823" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb6-824"><a href="#cb6-824" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-825"><a href="#cb6-825" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-826"><a href="#cb6-826" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-827"><a href="#cb6-827" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-828"><a href="#cb6-828" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-829"><a href="#cb6-829" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb6-830"><a href="#cb6-830" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-831"><a href="#cb6-831" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb6-832"><a href="#cb6-832" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb6-833"><a href="#cb6-833" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-834"><a href="#cb6-834" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T,</span>
<span id="cb6-835"><a href="#cb6-835" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-836"><a href="#cb6-836" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-837"><a href="#cb6-837" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-838"><a href="#cb6-838" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb6-839"><a href="#cb6-839" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb6-840"><a href="#cb6-840" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb6-841"><a href="#cb6-841" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb6-842"><a href="#cb6-842" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-843"><a href="#cb6-843" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-844"><a href="#cb6-844" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T,</span>
<span id="cb6-845"><a href="#cb6-845" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb6-846"><a href="#cb6-846" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-847"><a href="#cb6-847" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-848"><a href="#cb6-848" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb6-849"><a href="#cb6-849" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-850"><a href="#cb6-850" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb6-851"><a href="#cb6-851" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb6-852"><a href="#cb6-852" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb6-853"><a href="#cb6-853" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-854"><a href="#cb6-854" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-855"><a href="#cb6-855" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.rank2.syr2],</span></span>
<span id="cb6-856"><a href="#cb6-856" aria-hidden="true" tabindex="-1"></a><span class="co">// symmetric rank-2 matrix update</span></span>
<span id="cb6-857"><a href="#cb6-857" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb6-858"><a href="#cb6-858" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-859"><a href="#cb6-859" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-860"><a href="#cb6-860" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-861"><a href="#cb6-861" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_2_update<span class="op">(</span></span>
<span id="cb6-862"><a href="#cb6-862" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb6-863"><a href="#cb6-863" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb6-864"><a href="#cb6-864" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb6-865"><a href="#cb6-865" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-866"><a href="#cb6-866" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-867"><a href="#cb6-867" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-868"><a href="#cb6-868" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-869"><a href="#cb6-869" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-870"><a href="#cb6-870" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-871"><a href="#cb6-871" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_2_update<span class="op">(</span></span>
<span id="cb6-872"><a href="#cb6-872" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-873"><a href="#cb6-873" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb6-874"><a href="#cb6-874" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb6-875"><a href="#cb6-875" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb6-876"><a href="#cb6-876" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-877"><a href="#cb6-877" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-878"><a href="#cb6-878" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas2.rank2.her2],</span></span>
<span id="cb6-879"><a href="#cb6-879" aria-hidden="true" tabindex="-1"></a><span class="co">// Hermitian rank-2 matrix update</span></span>
<span id="cb6-880"><a href="#cb6-880" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb6-881"><a href="#cb6-881" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-882"><a href="#cb6-882" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-883"><a href="#cb6-883" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-884"><a href="#cb6-884" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_2_update<span class="op">(</span></span>
<span id="cb6-885"><a href="#cb6-885" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb6-886"><a href="#cb6-886" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb6-887"><a href="#cb6-887" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb6-888"><a href="#cb6-888" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-889"><a href="#cb6-889" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-890"><a href="#cb6-890" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb6-891"><a href="#cb6-891" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb6-892"><a href="#cb6-892" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-893"><a href="#cb6-893" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-894"><a href="#cb6-894" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_2_update<span class="op">(</span></span>
<span id="cb6-895"><a href="#cb6-895" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-896"><a href="#cb6-896" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb6-897"><a href="#cb6-897" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb6-898"><a href="#cb6-898" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb6-899"><a href="#cb6-899" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-900"><a href="#cb6-900" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-901"><a href="#cb6-901" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.gemm],</span></span>
<span id="cb6-902"><a href="#cb6-902" aria-hidden="true" tabindex="-1"></a><span class="co">// general matrix-matrix product</span></span>
<span id="cb6-903"><a href="#cb6-903" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-904"><a href="#cb6-904" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-905"><a href="#cb6-905" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-906"><a href="#cb6-906" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_product<span class="op">(</span>InMat1 A,</span>
<span id="cb6-907"><a href="#cb6-907" aria-hidden="true" tabindex="-1"></a>                    InMat2 B,</span>
<span id="cb6-908"><a href="#cb6-908" aria-hidden="true" tabindex="-1"></a>                    OutMat C<span class="op">)</span>;</span>
<span id="cb6-909"><a href="#cb6-909" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-910"><a href="#cb6-910" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-911"><a href="#cb6-911" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-912"><a href="#cb6-912" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-913"><a href="#cb6-913" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-914"><a href="#cb6-914" aria-hidden="true" tabindex="-1"></a>                    InMat1 A,</span>
<span id="cb6-915"><a href="#cb6-915" aria-hidden="true" tabindex="-1"></a>                    InMat2 B,</span>
<span id="cb6-916"><a href="#cb6-916" aria-hidden="true" tabindex="-1"></a>                    OutMat C<span class="op">)</span>;</span>
<span id="cb6-917"><a href="#cb6-917" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-918"><a href="#cb6-918" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-919"><a href="#cb6-919" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-920"><a href="#cb6-920" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-921"><a href="#cb6-921" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_product<span class="op">(</span>InMat1 A,</span>
<span id="cb6-922"><a href="#cb6-922" aria-hidden="true" tabindex="-1"></a>                    InMat2 B,</span>
<span id="cb6-923"><a href="#cb6-923" aria-hidden="true" tabindex="-1"></a>                    InMat3 E,</span>
<span id="cb6-924"><a href="#cb6-924" aria-hidden="true" tabindex="-1"></a>                    OutMat C<span class="op">)</span>;</span>
<span id="cb6-925"><a href="#cb6-925" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-926"><a href="#cb6-926" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-927"><a href="#cb6-927" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-928"><a href="#cb6-928" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-929"><a href="#cb6-929" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-930"><a href="#cb6-930" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-931"><a href="#cb6-931" aria-hidden="true" tabindex="-1"></a>                    InMat1 A,</span>
<span id="cb6-932"><a href="#cb6-932" aria-hidden="true" tabindex="-1"></a>                    InMat2 B,</span>
<span id="cb6-933"><a href="#cb6-933" aria-hidden="true" tabindex="-1"></a>                    InMat3 E,</span>
<span id="cb6-934"><a href="#cb6-934" aria-hidden="true" tabindex="-1"></a>                    OutMat C<span class="op">)</span>;</span>
<span id="cb6-935"><a href="#cb6-935" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-936"><a href="#cb6-936" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.symm],</span></span>
<span id="cb6-937"><a href="#cb6-937" aria-hidden="true" tabindex="-1"></a><span class="co">// symmetric matrix-matrix product</span></span>
<span id="cb6-938"><a href="#cb6-938" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-939"><a href="#cb6-939" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.symm.ov.left],</span></span>
<span id="cb6-940"><a href="#cb6-940" aria-hidden="true" tabindex="-1"></a><span class="co">// overwriting symmetric matrix-matrix left product</span></span>
<span id="cb6-941"><a href="#cb6-941" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-942"><a href="#cb6-942" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-943"><a href="#cb6-943" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-944"><a href="#cb6-944" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-945"><a href="#cb6-945" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_left_product<span class="op">(</span></span>
<span id="cb6-946"><a href="#cb6-946" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-947"><a href="#cb6-947" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-948"><a href="#cb6-948" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-949"><a href="#cb6-949" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-950"><a href="#cb6-950" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-951"><a href="#cb6-951" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-952"><a href="#cb6-952" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-953"><a href="#cb6-953" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-954"><a href="#cb6-954" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-955"><a href="#cb6-955" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_left_product<span class="op">(</span></span>
<span id="cb6-956"><a href="#cb6-956" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-957"><a href="#cb6-957" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-958"><a href="#cb6-958" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-959"><a href="#cb6-959" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-960"><a href="#cb6-960" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-961"><a href="#cb6-961" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-962"><a href="#cb6-962" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.symm.ov.right],</span></span>
<span id="cb6-963"><a href="#cb6-963" aria-hidden="true" tabindex="-1"></a><span class="co">// overwriting symmetric matrix-matrix right product</span></span>
<span id="cb6-964"><a href="#cb6-964" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-965"><a href="#cb6-965" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-966"><a href="#cb6-966" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-967"><a href="#cb6-967" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-968"><a href="#cb6-968" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_right_product<span class="op">(</span></span>
<span id="cb6-969"><a href="#cb6-969" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-970"><a href="#cb6-970" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-971"><a href="#cb6-971" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-972"><a href="#cb6-972" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-973"><a href="#cb6-973" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-974"><a href="#cb6-974" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-975"><a href="#cb6-975" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-976"><a href="#cb6-976" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-977"><a href="#cb6-977" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-978"><a href="#cb6-978" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_right_product<span class="op">(</span></span>
<span id="cb6-979"><a href="#cb6-979" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-980"><a href="#cb6-980" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-981"><a href="#cb6-981" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-982"><a href="#cb6-982" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-983"><a href="#cb6-983" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-984"><a href="#cb6-984" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-985"><a href="#cb6-985" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.symm.up.left],</span></span>
<span id="cb6-986"><a href="#cb6-986" aria-hidden="true" tabindex="-1"></a><span class="co">// updating symmetric matrix-matrix left product</span></span>
<span id="cb6-987"><a href="#cb6-987" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-988"><a href="#cb6-988" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-989"><a href="#cb6-989" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-990"><a href="#cb6-990" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-991"><a href="#cb6-991" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-992"><a href="#cb6-992" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_left_product<span class="op">(</span></span>
<span id="cb6-993"><a href="#cb6-993" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-994"><a href="#cb6-994" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-995"><a href="#cb6-995" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-996"><a href="#cb6-996" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb6-997"><a href="#cb6-997" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-998"><a href="#cb6-998" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-999"><a href="#cb6-999" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1000"><a href="#cb6-1000" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1001"><a href="#cb6-1001" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1002"><a href="#cb6-1002" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-1003"><a href="#cb6-1003" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1004"><a href="#cb6-1004" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_left_product<span class="op">(</span></span>
<span id="cb6-1005"><a href="#cb6-1005" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1006"><a href="#cb6-1006" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1007"><a href="#cb6-1007" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1008"><a href="#cb6-1008" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1009"><a href="#cb6-1009" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb6-1010"><a href="#cb6-1010" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1011"><a href="#cb6-1011" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1012"><a href="#cb6-1012" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.symm.up.right],</span></span>
<span id="cb6-1013"><a href="#cb6-1013" aria-hidden="true" tabindex="-1"></a><span class="co">// updating symmetric matrix-matrix right product</span></span>
<span id="cb6-1014"><a href="#cb6-1014" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1015"><a href="#cb6-1015" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1016"><a href="#cb6-1016" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1017"><a href="#cb6-1017" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-1018"><a href="#cb6-1018" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1019"><a href="#cb6-1019" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_right_product<span class="op">(</span></span>
<span id="cb6-1020"><a href="#cb6-1020" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1021"><a href="#cb6-1021" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1022"><a href="#cb6-1022" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1023"><a href="#cb6-1023" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb6-1024"><a href="#cb6-1024" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1025"><a href="#cb6-1025" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1026"><a href="#cb6-1026" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1027"><a href="#cb6-1027" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1028"><a href="#cb6-1028" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1029"><a href="#cb6-1029" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-1030"><a href="#cb6-1030" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1031"><a href="#cb6-1031" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_right_product<span class="op">(</span></span>
<span id="cb6-1032"><a href="#cb6-1032" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1033"><a href="#cb6-1033" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1034"><a href="#cb6-1034" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1035"><a href="#cb6-1035" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1036"><a href="#cb6-1036" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb6-1037"><a href="#cb6-1037" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1038"><a href="#cb6-1038" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1039"><a href="#cb6-1039" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.hemm],</span></span>
<span id="cb6-1040"><a href="#cb6-1040" aria-hidden="true" tabindex="-1"></a><span class="co">// Hermitian matrix-matrix product</span></span>
<span id="cb6-1041"><a href="#cb6-1041" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1042"><a href="#cb6-1042" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.hemm.ov.left],</span></span>
<span id="cb6-1043"><a href="#cb6-1043" aria-hidden="true" tabindex="-1"></a><span class="co">// overwriting Hermitian matrix-matrix left product</span></span>
<span id="cb6-1044"><a href="#cb6-1044" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1045"><a href="#cb6-1045" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1046"><a href="#cb6-1046" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1047"><a href="#cb6-1047" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1048"><a href="#cb6-1048" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_left_product<span class="op">(</span></span>
<span id="cb6-1049"><a href="#cb6-1049" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1050"><a href="#cb6-1050" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1051"><a href="#cb6-1051" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1052"><a href="#cb6-1052" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1053"><a href="#cb6-1053" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1054"><a href="#cb6-1054" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1055"><a href="#cb6-1055" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1056"><a href="#cb6-1056" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1057"><a href="#cb6-1057" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1058"><a href="#cb6-1058" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_left_product<span class="op">(</span></span>
<span id="cb6-1059"><a href="#cb6-1059" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1060"><a href="#cb6-1060" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1061"><a href="#cb6-1061" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1062"><a href="#cb6-1062" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1063"><a href="#cb6-1063" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1064"><a href="#cb6-1064" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1065"><a href="#cb6-1065" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.hemm.ov.right],</span></span>
<span id="cb6-1066"><a href="#cb6-1066" aria-hidden="true" tabindex="-1"></a><span class="co">// overwriting Hermitian matrix-matrix right product</span></span>
<span id="cb6-1067"><a href="#cb6-1067" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1068"><a href="#cb6-1068" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1069"><a href="#cb6-1069" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1070"><a href="#cb6-1070" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1071"><a href="#cb6-1071" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_right_product<span class="op">(</span></span>
<span id="cb6-1072"><a href="#cb6-1072" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1073"><a href="#cb6-1073" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1074"><a href="#cb6-1074" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1075"><a href="#cb6-1075" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1076"><a href="#cb6-1076" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1077"><a href="#cb6-1077" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1078"><a href="#cb6-1078" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1079"><a href="#cb6-1079" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1080"><a href="#cb6-1080" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1081"><a href="#cb6-1081" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_right_product<span class="op">(</span></span>
<span id="cb6-1082"><a href="#cb6-1082" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1083"><a href="#cb6-1083" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1084"><a href="#cb6-1084" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1085"><a href="#cb6-1085" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1086"><a href="#cb6-1086" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1087"><a href="#cb6-1087" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1088"><a href="#cb6-1088" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.hemm.up.left],</span></span>
<span id="cb6-1089"><a href="#cb6-1089" aria-hidden="true" tabindex="-1"></a><span class="co">// updating Hermitian matrix-matrix left product</span></span>
<span id="cb6-1090"><a href="#cb6-1090" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1091"><a href="#cb6-1091" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1092"><a href="#cb6-1092" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1093"><a href="#cb6-1093" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-1094"><a href="#cb6-1094" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1095"><a href="#cb6-1095" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_left_product<span class="op">(</span></span>
<span id="cb6-1096"><a href="#cb6-1096" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1097"><a href="#cb6-1097" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1098"><a href="#cb6-1098" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1099"><a href="#cb6-1099" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb6-1100"><a href="#cb6-1100" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1101"><a href="#cb6-1101" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1102"><a href="#cb6-1102" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1103"><a href="#cb6-1103" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1104"><a href="#cb6-1104" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1105"><a href="#cb6-1105" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-1106"><a href="#cb6-1106" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1107"><a href="#cb6-1107" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_left_product<span class="op">(</span></span>
<span id="cb6-1108"><a href="#cb6-1108" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1109"><a href="#cb6-1109" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1110"><a href="#cb6-1110" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1111"><a href="#cb6-1111" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1112"><a href="#cb6-1112" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb6-1113"><a href="#cb6-1113" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1114"><a href="#cb6-1114" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1115"><a href="#cb6-1115" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.hemm.up.right],</span></span>
<span id="cb6-1116"><a href="#cb6-1116" aria-hidden="true" tabindex="-1"></a><span class="co">// updating Hermitian matrix-matrix right product</span></span>
<span id="cb6-1117"><a href="#cb6-1117" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1118"><a href="#cb6-1118" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1119"><a href="#cb6-1119" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1120"><a href="#cb6-1120" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-1121"><a href="#cb6-1121" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1122"><a href="#cb6-1122" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_right_product<span class="op">(</span></span>
<span id="cb6-1123"><a href="#cb6-1123" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1124"><a href="#cb6-1124" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1125"><a href="#cb6-1125" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1126"><a href="#cb6-1126" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb6-1127"><a href="#cb6-1127" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1128"><a href="#cb6-1128" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1129"><a href="#cb6-1129" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1130"><a href="#cb6-1130" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1131"><a href="#cb6-1131" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1132"><a href="#cb6-1132" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-1133"><a href="#cb6-1133" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1134"><a href="#cb6-1134" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_right_product<span class="op">(</span></span>
<span id="cb6-1135"><a href="#cb6-1135" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1136"><a href="#cb6-1136" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1137"><a href="#cb6-1137" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1138"><a href="#cb6-1138" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1139"><a href="#cb6-1139" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb6-1140"><a href="#cb6-1140" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1141"><a href="#cb6-1141" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1142"><a href="#cb6-1142" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.trmm],</span></span>
<span id="cb6-1143"><a href="#cb6-1143" aria-hidden="true" tabindex="-1"></a><span class="co">// triangular matrix-matrix product</span></span>
<span id="cb6-1144"><a href="#cb6-1144" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1145"><a href="#cb6-1145" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.trmm.ov.left],</span></span>
<span id="cb6-1146"><a href="#cb6-1146" aria-hidden="true" tabindex="-1"></a><span class="co">// overwriting triangular matrix-matrix left product</span></span>
<span id="cb6-1147"><a href="#cb6-1147" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1148"><a href="#cb6-1148" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1149"><a href="#cb6-1149" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1150"><a href="#cb6-1150" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1151"><a href="#cb6-1151" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1152"><a href="#cb6-1152" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_left_product<span class="op">(</span></span>
<span id="cb6-1153"><a href="#cb6-1153" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1154"><a href="#cb6-1154" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1155"><a href="#cb6-1155" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1156"><a href="#cb6-1156" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1157"><a href="#cb6-1157" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1158"><a href="#cb6-1158" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1159"><a href="#cb6-1159" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1160"><a href="#cb6-1160" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1161"><a href="#cb6-1161" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1162"><a href="#cb6-1162" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1163"><a href="#cb6-1163" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1164"><a href="#cb6-1164" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_left_product<span class="op">(</span></span>
<span id="cb6-1165"><a href="#cb6-1165" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1166"><a href="#cb6-1166" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1167"><a href="#cb6-1167" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1168"><a href="#cb6-1168" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1169"><a href="#cb6-1169" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1170"><a href="#cb6-1170" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1171"><a href="#cb6-1171" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1172"><a href="#cb6-1172" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1173"><a href="#cb6-1173" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1174"><a href="#cb6-1174" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb6-1175"><a href="#cb6-1175" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_left_product<span class="op">(</span></span>
<span id="cb6-1176"><a href="#cb6-1176" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1177"><a href="#cb6-1177" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1178"><a href="#cb6-1178" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1179"><a href="#cb6-1179" aria-hidden="true" tabindex="-1"></a>  InOutMat C<span class="op">)</span>;</span>
<span id="cb6-1180"><a href="#cb6-1180" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1181"><a href="#cb6-1181" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1182"><a href="#cb6-1182" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1183"><a href="#cb6-1183" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1184"><a href="#cb6-1184" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb6-1185"><a href="#cb6-1185" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_left_product<span class="op">(</span></span>
<span id="cb6-1186"><a href="#cb6-1186" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1187"><a href="#cb6-1187" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1188"><a href="#cb6-1188" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1189"><a href="#cb6-1189" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1190"><a href="#cb6-1190" aria-hidden="true" tabindex="-1"></a>  InOutMat C<span class="op">)</span>;</span>
<span id="cb6-1191"><a href="#cb6-1191" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1192"><a href="#cb6-1192" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.trmm.ov.right],</span></span>
<span id="cb6-1193"><a href="#cb6-1193" aria-hidden="true" tabindex="-1"></a><span class="co">// overwriting triangular matrix-matrix right product</span></span>
<span id="cb6-1194"><a href="#cb6-1194" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1195"><a href="#cb6-1195" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1196"><a href="#cb6-1196" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1197"><a href="#cb6-1197" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1198"><a href="#cb6-1198" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1199"><a href="#cb6-1199" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_right_product<span class="op">(</span></span>
<span id="cb6-1200"><a href="#cb6-1200" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1201"><a href="#cb6-1201" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1202"><a href="#cb6-1202" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1203"><a href="#cb6-1203" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1204"><a href="#cb6-1204" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1205"><a href="#cb6-1205" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1206"><a href="#cb6-1206" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1207"><a href="#cb6-1207" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1208"><a href="#cb6-1208" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1209"><a href="#cb6-1209" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1210"><a href="#cb6-1210" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1211"><a href="#cb6-1211" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_right_product<span class="op">(</span></span>
<span id="cb6-1212"><a href="#cb6-1212" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1213"><a href="#cb6-1213" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1214"><a href="#cb6-1214" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1215"><a href="#cb6-1215" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1216"><a href="#cb6-1216" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1217"><a href="#cb6-1217" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1218"><a href="#cb6-1218" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1219"><a href="#cb6-1219" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1220"><a href="#cb6-1220" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1221"><a href="#cb6-1221" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb6-1222"><a href="#cb6-1222" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_right_product<span class="op">(</span></span>
<span id="cb6-1223"><a href="#cb6-1223" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1224"><a href="#cb6-1224" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1225"><a href="#cb6-1225" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1226"><a href="#cb6-1226" aria-hidden="true" tabindex="-1"></a>  InOutMat C<span class="op">)</span>;</span>
<span id="cb6-1227"><a href="#cb6-1227" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1228"><a href="#cb6-1228" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1229"><a href="#cb6-1229" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1230"><a href="#cb6-1230" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1231"><a href="#cb6-1231" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb6-1232"><a href="#cb6-1232" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_right_product<span class="op">(</span></span>
<span id="cb6-1233"><a href="#cb6-1233" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1234"><a href="#cb6-1234" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1235"><a href="#cb6-1235" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1236"><a href="#cb6-1236" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1237"><a href="#cb6-1237" aria-hidden="true" tabindex="-1"></a>  InOutMat C<span class="op">)</span>;</span>
<span id="cb6-1238"><a href="#cb6-1238" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1239"><a href="#cb6-1239" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.trmm.up.left],</span></span>
<span id="cb6-1240"><a href="#cb6-1240" aria-hidden="true" tabindex="-1"></a><span class="co">// updating triangular matrix-matrix left product</span></span>
<span id="cb6-1241"><a href="#cb6-1241" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1242"><a href="#cb6-1242" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1243"><a href="#cb6-1243" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1244"><a href="#cb6-1244" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1245"><a href="#cb6-1245" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-1246"><a href="#cb6-1246" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1247"><a href="#cb6-1247" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_left_product<span class="op">(</span></span>
<span id="cb6-1248"><a href="#cb6-1248" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1249"><a href="#cb6-1249" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1250"><a href="#cb6-1250" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1251"><a href="#cb6-1251" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1252"><a href="#cb6-1252" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb6-1253"><a href="#cb6-1253" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1254"><a href="#cb6-1254" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1255"><a href="#cb6-1255" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1256"><a href="#cb6-1256" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1257"><a href="#cb6-1257" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1258"><a href="#cb6-1258" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1259"><a href="#cb6-1259" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-1260"><a href="#cb6-1260" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1261"><a href="#cb6-1261" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_left_product<span class="op">(</span></span>
<span id="cb6-1262"><a href="#cb6-1262" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1263"><a href="#cb6-1263" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1264"><a href="#cb6-1264" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1265"><a href="#cb6-1265" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1266"><a href="#cb6-1266" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1267"><a href="#cb6-1267" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb6-1268"><a href="#cb6-1268" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1269"><a href="#cb6-1269" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1270"><a href="#cb6-1270" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.algs.blas3.trmm.up.right],</span></span>
<span id="cb6-1271"><a href="#cb6-1271" aria-hidden="true" tabindex="-1"></a><span class="co">// updating triangular matrix-matrix right product</span></span>
<span id="cb6-1272"><a href="#cb6-1272" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1273"><a href="#cb6-1273" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1274"><a href="#cb6-1274" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1275"><a href="#cb6-1275" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1276"><a href="#cb6-1276" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-1277"><a href="#cb6-1277" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1278"><a href="#cb6-1278" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_right_product<span class="op">(</span></span>
<span id="cb6-1279"><a href="#cb6-1279" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1280"><a href="#cb6-1280" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1281"><a href="#cb6-1281" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1282"><a href="#cb6-1282" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1283"><a href="#cb6-1283" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb6-1284"><a href="#cb6-1284" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1285"><a href="#cb6-1285" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1286"><a href="#cb6-1286" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1287"><a href="#cb6-1287" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1288"><a href="#cb6-1288" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1289"><a href="#cb6-1289" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1290"><a href="#cb6-1290" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb6-1291"><a href="#cb6-1291" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1292"><a href="#cb6-1292" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_right_product<span class="op">(</span></span>
<span id="cb6-1293"><a href="#cb6-1293" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1294"><a href="#cb6-1294" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1295"><a href="#cb6-1295" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1296"><a href="#cb6-1296" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1297"><a href="#cb6-1297" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1298"><a href="#cb6-1298" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb6-1299"><a href="#cb6-1299" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb6-1300"><a href="#cb6-1300" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1301"><a href="#cb6-1301" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.alg.blas3.rank-k.syrk],</span></span>
<span id="cb6-1302"><a href="#cb6-1302" aria-hidden="true" tabindex="-1"></a><span class="co">// rank-k symmetric matrix update</span></span>
<span id="cb6-1303"><a href="#cb6-1303" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T,</span>
<span id="cb6-1304"><a href="#cb6-1304" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1305"><a href="#cb6-1305" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-1306"><a href="#cb6-1306" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-1307"><a href="#cb6-1307" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb6-1308"><a href="#cb6-1308" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb6-1309"><a href="#cb6-1309" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1310"><a href="#cb6-1310" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb6-1311"><a href="#cb6-1311" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-1312"><a href="#cb6-1312" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T,</span>
<span id="cb6-1313"><a href="#cb6-1313" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1314"><a href="#cb6-1314" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1315"><a href="#cb6-1315" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-1316"><a href="#cb6-1316" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-1317"><a href="#cb6-1317" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb6-1318"><a href="#cb6-1318" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1319"><a href="#cb6-1319" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb6-1320"><a href="#cb6-1320" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1321"><a href="#cb6-1321" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb6-1322"><a href="#cb6-1322" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-1323"><a href="#cb6-1323" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1324"><a href="#cb6-1324" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.alg.blas3.rank-k.herk],</span></span>
<span id="cb6-1325"><a href="#cb6-1325" aria-hidden="true" tabindex="-1"></a><span class="co">// rank-k Hermitian matrix update</span></span>
<span id="cb6-1326"><a href="#cb6-1326" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T,</span>
<span id="cb6-1327"><a href="#cb6-1327" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1328"><a href="#cb6-1328" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-1329"><a href="#cb6-1329" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-1330"><a href="#cb6-1330" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb6-1331"><a href="#cb6-1331" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb6-1332"><a href="#cb6-1332" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1333"><a href="#cb6-1333" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb6-1334"><a href="#cb6-1334" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-1335"><a href="#cb6-1335" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1336"><a href="#cb6-1336" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T,</span>
<span id="cb6-1337"><a href="#cb6-1337" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1338"><a href="#cb6-1338" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-1339"><a href="#cb6-1339" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-1340"><a href="#cb6-1340" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb6-1341"><a href="#cb6-1341" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1342"><a href="#cb6-1342" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb6-1343"><a href="#cb6-1343" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1344"><a href="#cb6-1344" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb6-1345"><a href="#cb6-1345" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-1346"><a href="#cb6-1346" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1347"><a href="#cb6-1347" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.alg.blas3.rank2k.syr2k],</span></span>
<span id="cb6-1348"><a href="#cb6-1348" aria-hidden="true" tabindex="-1"></a><span class="co">// rank-2k symmetric matrix update</span></span>
<span id="cb6-1349"><a href="#cb6-1349" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1350"><a href="#cb6-1350" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1351"><a href="#cb6-1351" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-1352"><a href="#cb6-1352" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-1353"><a href="#cb6-1353" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb6-1354"><a href="#cb6-1354" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1355"><a href="#cb6-1355" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1356"><a href="#cb6-1356" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb6-1357"><a href="#cb6-1357" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-1358"><a href="#cb6-1358" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1359"><a href="#cb6-1359" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1360"><a href="#cb6-1360" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1361"><a href="#cb6-1361" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-1362"><a href="#cb6-1362" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-1363"><a href="#cb6-1363" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb6-1364"><a href="#cb6-1364" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1365"><a href="#cb6-1365" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1366"><a href="#cb6-1366" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1367"><a href="#cb6-1367" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb6-1368"><a href="#cb6-1368" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-1369"><a href="#cb6-1369" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1370"><a href="#cb6-1370" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.alg.blas3.rank2k.her2k],</span></span>
<span id="cb6-1371"><a href="#cb6-1371" aria-hidden="true" tabindex="-1"></a><span class="co">// rank-2k Hermitian matrix update</span></span>
<span id="cb6-1372"><a href="#cb6-1372" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1373"><a href="#cb6-1373" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1374"><a href="#cb6-1374" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-1375"><a href="#cb6-1375" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-1376"><a href="#cb6-1376" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb6-1377"><a href="#cb6-1377" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1378"><a href="#cb6-1378" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1379"><a href="#cb6-1379" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb6-1380"><a href="#cb6-1380" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-1381"><a href="#cb6-1381" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1382"><a href="#cb6-1382" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1383"><a href="#cb6-1383" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1384"><a href="#cb6-1384" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb6-1385"><a href="#cb6-1385" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb6-1386"><a href="#cb6-1386" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb6-1387"><a href="#cb6-1387" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1388"><a href="#cb6-1388" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1389"><a href="#cb6-1389" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1390"><a href="#cb6-1390" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb6-1391"><a href="#cb6-1391" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb6-1392"><a href="#cb6-1392" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1393"><a href="#cb6-1393" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.alg.blas3.trsm],</span></span>
<span id="cb6-1394"><a href="#cb6-1394" aria-hidden="true" tabindex="-1"></a><span class="co">// solve multiple triangular linear systems</span></span>
<span id="cb6-1395"><a href="#cb6-1395" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1396"><a href="#cb6-1396" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.alg.blas3.trsm.left],</span></span>
<span id="cb6-1397"><a href="#cb6-1397" aria-hidden="true" tabindex="-1"></a><span class="co">// solve multiple triangular linear systems</span></span>
<span id="cb6-1398"><a href="#cb6-1398" aria-hidden="true" tabindex="-1"></a><span class="co">// with triangular matrix on the left</span></span>
<span id="cb6-1399"><a href="#cb6-1399" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1400"><a href="#cb6-1400" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1401"><a href="#cb6-1401" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1402"><a href="#cb6-1402" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1403"><a href="#cb6-1403" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat,</span>
<span id="cb6-1404"><a href="#cb6-1404" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb6-1405"><a href="#cb6-1405" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb6-1406"><a href="#cb6-1406" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1407"><a href="#cb6-1407" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1408"><a href="#cb6-1408" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1409"><a href="#cb6-1409" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1410"><a href="#cb6-1410" aria-hidden="true" tabindex="-1"></a>  OutMat X,</span>
<span id="cb6-1411"><a href="#cb6-1411" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb6-1412"><a href="#cb6-1412" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1413"><a href="#cb6-1413" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1414"><a href="#cb6-1414" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1415"><a href="#cb6-1415" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1416"><a href="#cb6-1416" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1417"><a href="#cb6-1417" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat,</span>
<span id="cb6-1418"><a href="#cb6-1418" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb6-1419"><a href="#cb6-1419" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb6-1420"><a href="#cb6-1420" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1421"><a href="#cb6-1421" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1422"><a href="#cb6-1422" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1423"><a href="#cb6-1423" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1424"><a href="#cb6-1424" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1425"><a href="#cb6-1425" aria-hidden="true" tabindex="-1"></a>  OutMat X,</span>
<span id="cb6-1426"><a href="#cb6-1426" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb6-1427"><a href="#cb6-1427" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1428"><a href="#cb6-1428" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1429"><a href="#cb6-1429" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1430"><a href="#cb6-1430" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat,</span>
<span id="cb6-1431"><a href="#cb6-1431" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb6-1432"><a href="#cb6-1432" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb6-1433"><a href="#cb6-1433" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1434"><a href="#cb6-1434" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1435"><a href="#cb6-1435" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1436"><a href="#cb6-1436" aria-hidden="true" tabindex="-1"></a>  InOutMat B,</span>
<span id="cb6-1437"><a href="#cb6-1437" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb6-1438"><a href="#cb6-1438" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1439"><a href="#cb6-1439" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1440"><a href="#cb6-1440" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1441"><a href="#cb6-1441" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1442"><a href="#cb6-1442" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat,</span>
<span id="cb6-1443"><a href="#cb6-1443" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb6-1444"><a href="#cb6-1444" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb6-1445"><a href="#cb6-1445" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1446"><a href="#cb6-1446" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1447"><a href="#cb6-1447" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1448"><a href="#cb6-1448" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1449"><a href="#cb6-1449" aria-hidden="true" tabindex="-1"></a>  InOutMat B,</span>
<span id="cb6-1450"><a href="#cb6-1450" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb6-1451"><a href="#cb6-1451" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1452"><a href="#cb6-1452" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1453"><a href="#cb6-1453" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1454"><a href="#cb6-1454" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1455"><a href="#cb6-1455" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1456"><a href="#cb6-1456" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1457"><a href="#cb6-1457" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb6-1458"><a href="#cb6-1458" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1459"><a href="#cb6-1459" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1460"><a href="#cb6-1460" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1461"><a href="#cb6-1461" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1462"><a href="#cb6-1462" aria-hidden="true" tabindex="-1"></a>  OutMat X<span class="op">)</span>;</span>
<span id="cb6-1463"><a href="#cb6-1463" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1464"><a href="#cb6-1464" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1465"><a href="#cb6-1465" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1466"><a href="#cb6-1466" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1467"><a href="#cb6-1467" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1468"><a href="#cb6-1468" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1469"><a href="#cb6-1469" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb6-1470"><a href="#cb6-1470" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1471"><a href="#cb6-1471" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1472"><a href="#cb6-1472" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1473"><a href="#cb6-1473" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1474"><a href="#cb6-1474" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1475"><a href="#cb6-1475" aria-hidden="true" tabindex="-1"></a>  OutMat X<span class="op">)</span>;</span>
<span id="cb6-1476"><a href="#cb6-1476" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1477"><a href="#cb6-1477" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1478"><a href="#cb6-1478" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1479"><a href="#cb6-1479" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb6-1480"><a href="#cb6-1480" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb6-1481"><a href="#cb6-1481" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1482"><a href="#cb6-1482" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1483"><a href="#cb6-1483" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1484"><a href="#cb6-1484" aria-hidden="true" tabindex="-1"></a>  InOutMat B<span class="op">)</span>;</span>
<span id="cb6-1485"><a href="#cb6-1485" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1486"><a href="#cb6-1486" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1487"><a href="#cb6-1487" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1488"><a href="#cb6-1488" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1489"><a href="#cb6-1489" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb6-1490"><a href="#cb6-1490" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb6-1491"><a href="#cb6-1491" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1492"><a href="#cb6-1492" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1493"><a href="#cb6-1493" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1494"><a href="#cb6-1494" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1495"><a href="#cb6-1495" aria-hidden="true" tabindex="-1"></a>  InOutMat B<span class="op">)</span>;</span>
<span id="cb6-1496"><a href="#cb6-1496" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1497"><a href="#cb6-1497" aria-hidden="true" tabindex="-1"></a><span class="co">// [linalg.alg.blas3.trsm.right],</span></span>
<span id="cb6-1498"><a href="#cb6-1498" aria-hidden="true" tabindex="-1"></a><span class="co">// solve multiple triangular linear systems</span></span>
<span id="cb6-1499"><a href="#cb6-1499" aria-hidden="true" tabindex="-1"></a><span class="co">// with triangular matrix on the right</span></span>
<span id="cb6-1500"><a href="#cb6-1500" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1501"><a href="#cb6-1501" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1502"><a href="#cb6-1502" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1503"><a href="#cb6-1503" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1504"><a href="#cb6-1504" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat,</span>
<span id="cb6-1505"><a href="#cb6-1505" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb6-1506"><a href="#cb6-1506" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb6-1507"><a href="#cb6-1507" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1508"><a href="#cb6-1508" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1509"><a href="#cb6-1509" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1510"><a href="#cb6-1510" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1511"><a href="#cb6-1511" aria-hidden="true" tabindex="-1"></a>  OutMat X,</span>
<span id="cb6-1512"><a href="#cb6-1512" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb6-1513"><a href="#cb6-1513" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1514"><a href="#cb6-1514" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1515"><a href="#cb6-1515" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1516"><a href="#cb6-1516" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1517"><a href="#cb6-1517" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1518"><a href="#cb6-1518" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat,</span>
<span id="cb6-1519"><a href="#cb6-1519" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb6-1520"><a href="#cb6-1520" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb6-1521"><a href="#cb6-1521" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1522"><a href="#cb6-1522" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-1523"><a href="#cb6-1523" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1524"><a href="#cb6-1524" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1525"><a href="#cb6-1525" aria-hidden="true" tabindex="-1"></a>  InMat B,</span>
<span id="cb6-1526"><a href="#cb6-1526" aria-hidden="true" tabindex="-1"></a>  OutMat X,</span>
<span id="cb6-1527"><a href="#cb6-1527" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb6-1528"><a href="#cb6-1528" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1529"><a href="#cb6-1529" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1530"><a href="#cb6-1530" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1531"><a href="#cb6-1531" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat,</span>
<span id="cb6-1532"><a href="#cb6-1532" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb6-1533"><a href="#cb6-1533" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb6-1534"><a href="#cb6-1534" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1535"><a href="#cb6-1535" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1536"><a href="#cb6-1536" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1537"><a href="#cb6-1537" aria-hidden="true" tabindex="-1"></a>  InOutMat B,</span>
<span id="cb6-1538"><a href="#cb6-1538" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb6-1539"><a href="#cb6-1539" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1540"><a href="#cb6-1540" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1541"><a href="#cb6-1541" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1542"><a href="#cb6-1542" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1543"><a href="#cb6-1543" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat,</span>
<span id="cb6-1544"><a href="#cb6-1544" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb6-1545"><a href="#cb6-1545" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb6-1546"><a href="#cb6-1546" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1547"><a href="#cb6-1547" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1548"><a href="#cb6-1548" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1549"><a href="#cb6-1549" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1550"><a href="#cb6-1550" aria-hidden="true" tabindex="-1"></a>  InOutMat B,</span>
<span id="cb6-1551"><a href="#cb6-1551" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb6-1552"><a href="#cb6-1552" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-1553"><a href="#cb6-1553" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1554"><a href="#cb6-1554" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1555"><a href="#cb6-1555" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1556"><a href="#cb6-1556" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1557"><a href="#cb6-1557" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1558"><a href="#cb6-1558" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb6-1559"><a href="#cb6-1559" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1560"><a href="#cb6-1560" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1561"><a href="#cb6-1561" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1562"><a href="#cb6-1562" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb6-1563"><a href="#cb6-1563" aria-hidden="true" tabindex="-1"></a>  OutMat X<span class="op">)</span>;</span>
<span id="cb6-1564"><a href="#cb6-1564" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1565"><a href="#cb6-1565" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1566"><a href="#cb6-1566" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1567"><a href="#cb6-1567" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1568"><a href="#cb6-1568" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb6-1569"><a href="#cb6-1569" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb6-1570"><a href="#cb6-1570" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb6-1571"><a href="#cb6-1571" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1572"><a href="#cb6-1572" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb6-1573"><a href="#cb6-1573" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1574"><a href="#cb6-1574" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1575"><a href="#cb6-1575" aria-hidden="true" tabindex="-1"></a>  InMat B,</span>
<span id="cb6-1576"><a href="#cb6-1576" aria-hidden="true" tabindex="-1"></a>  OutMat X<span class="op">)</span>;</span>
<span id="cb6-1577"><a href="#cb6-1577" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb6-1578"><a href="#cb6-1578" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1579"><a href="#cb6-1579" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1580"><a href="#cb6-1580" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb6-1581"><a href="#cb6-1581" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb6-1582"><a href="#cb6-1582" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1583"><a href="#cb6-1583" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1584"><a href="#cb6-1584" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1585"><a href="#cb6-1585" aria-hidden="true" tabindex="-1"></a>  InOutMat B<span class="op">)</span>;</span>
<span id="cb6-1586"><a href="#cb6-1586" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb6-1587"><a href="#cb6-1587" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb6-1588"><a href="#cb6-1588" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb6-1589"><a href="#cb6-1589" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb6-1590"><a href="#cb6-1590" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb6-1591"><a href="#cb6-1591" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb6-1592"><a href="#cb6-1592" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb6-1593"><a href="#cb6-1593" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb6-1594"><a href="#cb6-1594" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb6-1595"><a href="#cb6-1595" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb6-1596"><a href="#cb6-1596" aria-hidden="true" tabindex="-1"></a>  InOutMat B<span class="op">)</span>;</span>
<span id="cb6-1597"><a href="#cb6-1597" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="16.2" id="requirements-linalg.reqs"><span class="header-section-number">16.2</span> Requirements [linalg.reqs]<a href="#requirements-linalg.reqs" class="self-link"></a></h2>
<h3 data-number="16.2.1" id="value-and-reference-requirements-linalg.reqs.val"><span class="header-section-number">16.2.1</span> Value and reference
requirements [linalg.reqs.val]<a href="#value-and-reference-requirements-linalg.reqs.val" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
This clause lists the minimum requirements for all algorithms and
classes in <strong>[linalg]</strong>, and for the following types:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> for
any input or output <code>mdspan</code> parameter(s) of any algorithm or
method in <strong>[linalg]</strong>, the parameter(s)’
<code>value_type</code> and <code>reference</code> type
aliases;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> the
<code>Scalar</code> template parameter (if any) of any algorithm or
class in <strong>[linalg]</strong>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span> the
<code>T</code> template parameter of any algorithm in
<strong>[linalg]</strong> with a <code>T init</code> parameter;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span> the
template parameter of <code>sum_of_squares_result</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
In this clause, we refer to these types as <em>linear algebra value
types</em>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
All of the following requirements presume that the algorithm’s
asymptotic complexity requirements, if any, are satisfied.</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> Any
linear algebra value type meets the requirements of
<code>semiregular</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> The
algorithm or method may perform read-only access on any input or output
<code>mdspan</code> arbitrarily many times.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span> The
algorithm or method may make arbitrarily many objects of any linear
algebra value type, value-initializing or direct-initializing them with
any existing object of that type.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.4)</a></span> The
algorithm or method may assign arbitrarily many times to any reference
resulting from a valid output <code>mdspan</code> access.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.5)</a></span> The
<em>triangular solve algorithms</em> in <strong>[linalg.algs]</strong>
either have a <code>BinaryDivideOp</code> template parameter (see
<strong>[linalg.algs.reqs]</strong>) and a binary function object
parameter <code>divide</code> of that type, or they have effects
equivalent to invoking such an algorithm. Triangular solve algorithms
interpret <code>divide(a, b)</code> as <code>a</code> times the
multiplicative inverse of <code>b</code>. Each triangular solve
algorithm uses a sequence of evaluations of <code>*</code>,
<code>*=</code>, <code>divide</code>, <code>+</code>, <code>+=</code>,
unary <code>-</code>, binary <code>-</code>, <code>-=</code>, and
<code>=</code> operators that would produce the result specified by the
algorithm’s Effects and Remarks when operating on elements of a field
with noncommutative multiplication. It is a constraint on the algorithm
that any addend, any subtrahend, any partial sum of addends in any order
(treating any difference as a sum with the second term negated), any
factor, any partial product of factors respecting their order, any
numerator (first argument of <code>divide</code>), any denominator
(second argument of <code>divide</code>), and any assignment is well
formed.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.6)</a></span>
Otherwise, the algorithm or method will use a sequence of evaluations of
<code>*</code>, <code>*=</code>, <code>+</code>, <code>+=</code>, and
<code>=</code> operators that would produce the result specified by the
algorithm’s Effects and Remarks when operating on elements of a semiring
with noncommutative multiplication. It is a constraint on the algorithm
that any addend, any partial sum of addends in any order, any factor,
any partial product of factors respecting their order, and any
assignment is well formed.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.7)</a></span> If
the wording for the algorithm or method additionally includes</p>
<ul>
<li><p><em><code>conj-if-needed</code></em><code>(z)</code> for some
expression <code>z</code>
(<strong>[linalg.scaled.conj]</strong>)</p></li>
<li><p><code>abs(x)</code> for some expression <code>x</code>,
or</p></li>
<li><p><code>sqrt(x)</code> for some expression <code>x</code>,</p></li>
</ul>
<p>then it is a constraint on the algorithm that use of the relevant
expression where it would be mathematically appropriate is well
formed.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.10)</a></span> If
the algorithm or method has an output <code>mdspan</code>, then all
addends (or subtrahends, if applicable) (or results of
<code>divide</code> on intermediate terms, if applicable) are assignable
and convertible to the output <code>mdspan</code>’s
<code>value_type</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.11)</a></span> The
algorithm or method may reorder addends and partial sums arbitrarily.
<i>[Note:</i> Factors in each product are not reordered; multiplication
is not necessarily commutative. <i>– end note]</i></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.12)</a></span> The
algorithm or method may replace any value with the sum of that value and
a value-initialized object of any input or output <code>mdspan</code>’s
<code>value_type</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.13)</a></span> If
the algorithm or method has a <code>T init</code> parameter, then the
algorithm or method may replace any value with the sum of that value and
a value-initialized object of type <code>T</code>.</p></li>
</ul>
<h3 data-number="16.2.2" id="requirements-for-algorithms-and-methods-on-floating-point-values-linalg.reqs.flpt"><span class="header-section-number">16.2.2</span> Requirements for algorithms
and methods on floating-point values [linalg.reqs.flpt]<a href="#requirements-for-algorithms-and-methods-on-floating-point-values-linalg.reqs.flpt" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
For all algorithms and classes in <strong>[linalg]</strong>, suppose
that</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> all
input and output <code>mdspan</code> have <code>value_type</code> a
floating-point type,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> any
<code>Scalar</code> template argument has a floating-point type,
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span> any
argument corresponding to the <code>T init</code> parameter has a
floating-point type.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Then, algorithms and classes’ methods may do the following:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
compute floating-point sums in any way that improves their accuracy for
arbitrary input;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
perform additional arithmetic operations (other than those specified by
the algorithm’s or method’s wording and
<strong>[linalg.reqs.val]</strong>) in order to improve performance or
accuracy; and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span> use
approximations (that might not be exact even if computing with real
numbers), instead of computations that would be exact if it were
possible to compute without rounding error;</p></li>
</ul>
<p>as long as</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.4)</a></span> the
algorithm or method satisfies the complexity requirements; and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.5)</a></span> the
algorithm or method is <em>logarithmically stable</em>, as defined in J.
Demmel, I. Dumitriu, and O. Holtz, “Fast linear algebra is stable,”
<em>Numerische Mathematik</em> 108 (59-91), 2007. <i>[Note:</i>
Strassen’s algorithm for matrix-matrix multiply is an example of a
logarithmically stable algorithm. <i>– end note]</i></p></li>
</ul>
<h2 data-number="16.3" id="tag-classes-linalg.tags"><span class="header-section-number">16.3</span> Tag classes [linalg.tags]<a href="#tag-classes-linalg.tags" class="self-link"></a></h2>
<h3 data-number="16.3.1" id="storage-order-tags-linalg.tags.order"><span class="header-section-number">16.3.1</span> Storage order tags
[linalg.tags.order]<a href="#storage-order-tags-linalg.tags.order" class="self-link"></a></h3>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> column_major_t <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">explicit</span> column_major_t<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> column_major_t column_major <span class="op">=</span> <span class="op">{</span> <span class="op">}</span>;</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> row_major_t <span class="op">{</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">explicit</span> row_major_t<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> row_major_t row_major <span class="op">=</span> <span class="op">{</span> <span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<code>column_major_t</code> indicates a column-major order, and
<code>row_major_t</code> indicates a row-major order. The interpretation
of each depends on the specific layout that uses the tag. See
<code>layout_blas_packed</code> below.</p>
<h3 data-number="16.3.2" id="triangle-tags-linalg.tags.triangle"><span class="header-section-number">16.3.2</span> Triangle tags
[linalg.tags.triangle]<a href="#triangle-tags-linalg.tags.triangle" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Some linear algebra algorithms distinguish between the “upper triangle,”
“lower triangle,” and “diagonal” of a matrix.</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> The
<em>diagonal</em> is the set of all elements of <code>A</code> accessed
by <code>A[i,i]</code> for 0 ≤ <code>i</code> &lt;
min(<code>A.extent(0)</code>, <code>A.extent(1)</code>).</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> The
<em>upper triangle</em> of a matrix <code>A</code> is the set of all
elements of <code>A</code> accessed by <code>A[i,j]</code> with
<code>i</code> ≤ <code>j</code>. It includes the diagonal.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span> The
<em>lower triangle</em> of <code>A</code> is the set of all elements of
<code>A</code> accessed by <code>A[i,j]</code> with <code>i</code> ≥
<code>j</code>. It includes the diagonal.</p></li>
</ul>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> upper_triangle_t <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">explicit</span> upper_triangle_t<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> upper_triangle_t upper_triangle <span class="op">=</span> <span class="op">{</span> <span class="op">}</span>;</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> lower_triangle_t <span class="op">{</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">explicit</span> lower_triangle_t<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> lower_triangle_t lower_triangle <span class="op">=</span> <span class="op">{</span> <span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
These tag classes specify whether algorithms and other users of a matrix
(represented as an <code>mdspan</code>) should access the upper triangle
(<code>upper_triangular_t</code>) or lower triangle
(<code>lower_triangular_t</code>) of the matrix. This is also subject to
the restrictions of <code>implicit_unit_diagonal_t</code> if that tag is
also applied; see below.</p>
<p><i>[Note:</i> The <code>conjugate_transposed</code> and
<code>transposed</code> functions in this section return a view of an
input <code>mdspan</code> with its rightmost two indices effectively
reversed. Regardless, when we refer to the upper triangle of
<code>B = transposed(A)</code>, we still mean the elements of
<code>B</code> accessed by <code>B[i,j]</code> with <code>i</code> ≤
<code>j</code>. For all algorithms in this section that take a triangle
tag parameter, the triangle tag refers to the actual input matrix,
<em>after</em> any transformations like <code>transposed</code>. This
differs from the BLAS’ <code>UPLO</code> argument, which refers to the
pre-transformed “original” matrix. <i>– end note]</i></p>
<h3 data-number="16.3.3" id="diagonal-tags-linalg.tags.diagonal"><span class="header-section-number">16.3.3</span> Diagonal tags
[linalg.tags.diagonal]<a href="#diagonal-tags-linalg.tags.diagonal" class="self-link"></a></h3>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> implicit_unit_diagonal_t <span class="op">{</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">explicit</span> implicit_unit_diagonal_t<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> implicit_unit_diagonal_t</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  implicit_unit_diagonal <span class="op">=</span> <span class="op">{</span> <span class="op">}</span>;</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> explicit_diagonal_t <span class="op">{</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">explicit</span> explicit_diagonal_t<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> explicit_diagonal_t explicit_diagonal <span class="op">=</span> <span class="op">{</span> <span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
These tag classes specify whether algorithms should access the matrix’s
diagonal entries, and if not, then how algorithms should interpret the
matrix’s implicitly represented diagonal values.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The <code>implicit_unit_diagonal_t</code> tag indicates two things:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> the
algorithm will never access the <code>i,i</code> element of the matrix
for any <code>i</code>; and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span> the
algorithm will interpret the matrix as if it has a “unit diagonal,” a
diagonal each of whose elements behaves as a two-sided multiplicative
identity (even if the matrix’s value type does not have a two-sided
multiplicative identity).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
The tag <code>explicit_diagonal_t</code> indicates that algorithms may
access the matrix’s diagonal entries directly.</p>
<h2 data-number="16.4" id="layouts-for-packed-matrix-types-linalg.layouts"><span class="header-section-number">16.4</span> Layouts for packed matrix
types [linalg.layouts]<a href="#layouts-for-packed-matrix-types-linalg.layouts" class="self-link"></a></h2>
<h3 data-number="16.4.1" id="layout_blas_packed-linalg.layouts.packed"><span class="header-section-number">16.4.1</span>
<code>layout_blas_packed</code> [linalg.layouts.packed]<a href="#layout_blas_packed-linalg.layouts.packed" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<code>layout_blas_packed</code> is an <code>mdspan</code> layout mapping
policy that represents a square matrix that stores only the entries in
one triangle, in a packed contiguous format. Its <code>Triangle</code>
template parameter determines whether an <code>mdspan</code> with this
layout stores the upper or lower triangle of the matrix. Its
<code>StorageOrder</code> template parameter determines whether the
layout packs the matrix’s elements in column-major or row-major
order.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
A <code>StorageOrder</code> of <code>column_major_t</code> indicates
column-major ordering. This packs matrix elements starting with the
leftmost (least column index) column, and proceeding column by column,
from the top entry (least row index).</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
A <code>StorageOrder</code> of <code>row_major_t</code> indicates
row-major ordering. This packs matrix elements starting with the topmost
(least row index) row, and proceeding row by row, from the leftmost
(least column index) entry.</p>
<p><i>[Note:</i> <code>layout_blas_packed</code> describes the data
layout used by the BLAS’ Symmetric Packed (SP), Hermitian Packed (HP),
and Triangular Packed (TP) matrix types. <i>– end note]</i></p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Triangle,</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> StorageOrder<span class="op">&gt;</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> layout_blas_packed <span class="op">{</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> mapping <span class="op">{</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">public</span><span class="op">:</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> extents_type <span class="op">=</span> Extents;</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> index_type <span class="op">=</span> <span class="kw">typename</span> extents_type<span class="op">::</span>index_type;</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> size_type <span class="op">=</span> <span class="kw">typename</span> extents_type<span class="op">::</span>size_type;</span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> rank_type <span class="op">=</span> <span class="kw">typename</span> extents_type<span class="op">::</span>rank_type;</span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> layout_type <span class="op">=</span> layout_blas_packed<span class="op">&lt;</span>Triangle, StorageOrder<span class="op">&gt;</span>;</span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">private</span><span class="op">:</span></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a>    Extents <em>the-extents</em><span class="op">{}</span>; <span class="co">// exposition only</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a>  <span class="kw">public</span><span class="op">:</span></span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> mapping<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> mapping<span class="op">&amp;)</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> e<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true" tabindex="-1"></a>        mapping<span class="op">(</span><span class="kw">const</span> mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-25"><a href="#cb10-25" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> mapping<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> mapping<span class="op">&amp;)</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb10-26"><a href="#cb10-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-27"><a href="#cb10-27" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> extents_type extents<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <em>the-extents</em>; <span class="op">}</span></span>
<span id="cb10-28"><a href="#cb10-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-29"><a href="#cb10-29" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> size_type required_span_size<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb10-30"><a href="#cb10-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-31"><a href="#cb10-31" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Indices<span class="op">&gt;</span></span>
<span id="cb10-32"><a href="#cb10-32" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> index_type <span class="kw">operator</span><span class="op">()</span> <span class="op">(</span>Indices<span class="op">...)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb10-33"><a href="#cb10-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-34"><a href="#cb10-34" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_unique<span class="op">()</span> <span class="op">{</span></span>
<span id="cb10-35"><a href="#cb10-35" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> extents_type<span class="op">::</span>static_extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">!=</span> dynamic_extent <span class="op">&amp;&amp;</span></span>
<span id="cb10-36"><a href="#cb10-36" aria-hidden="true" tabindex="-1"></a>        extents_type<span class="op">::</span>static_extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">&lt;</span> <span class="dv">2</span>;</span>
<span id="cb10-37"><a href="#cb10-37" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-38"><a href="#cb10-38" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_exhaustive<span class="op">()</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">true</span>; <span class="op">}</span></span>
<span id="cb10-39"><a href="#cb10-39" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_strided<span class="op">()</span> <span class="op">{</span></span>
<span id="cb10-40"><a href="#cb10-40" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> extents_type<span class="op">::</span>static_extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">!=</span> dynamic_extent <span class="op">&amp;&amp;</span></span>
<span id="cb10-41"><a href="#cb10-41" aria-hidden="true" tabindex="-1"></a>        extents_type<span class="op">::</span>static_extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">&lt;</span> <span class="dv">2</span>;</span>
<span id="cb10-42"><a href="#cb10-42" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-43"><a href="#cb10-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-44"><a href="#cb10-44" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> is_unique<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb10-45"><a href="#cb10-45" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">&lt;</span> <span class="dv">2</span>;</span>
<span id="cb10-46"><a href="#cb10-46" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-47"><a href="#cb10-47" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> is_exhaustive<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">true</span>; <span class="op">}</span></span>
<span id="cb10-48"><a href="#cb10-48" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> is_strided<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb10-49"><a href="#cb10-49" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">&lt;</span> <span class="dv">2</span>;</span>
<span id="cb10-50"><a href="#cb10-50" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-51"><a href="#cb10-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-52"><a href="#cb10-52" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> index_type stride<span class="op">(</span>rank_type<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb10-53"><a href="#cb10-53" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-54"><a href="#cb10-54" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb10-55"><a href="#cb10-55" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span></span>
<span id="cb10-56"><a href="#cb10-56" aria-hidden="true" tabindex="-1"></a>        <span class="kw">operator</span><span class="op">==(</span><span class="kw">const</span> mapping<span class="op">&amp;</span>, <span class="kw">const</span> mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb10-57"><a href="#cb10-57" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<code>Triangle</code> is either <code>upper_triangle_t</code> or
<code>lower_triangle_t</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
<code>StorageOrder</code> is either <code>column_major_t</code> or
<code>row_major_t</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span>
<code>Extents</code> is a specialization of
<code>extents</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.4)</a></span>
<code>Extents::rank()</code> equals 2.</p></li>
</ul>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> e<span class="op">)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span> The
size of the multidimensional index space <code>e</code> is representable
as a value of type <code>index_type</code>
(<strong>[basic.fundamental]</strong>), and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
<code>e.extent(0)</code> equals <code>e.extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Effects:</em> Direct-non-list-initializes
<em><code>the-extents</code></em> with <code>e</code>.</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Constraints:</em>
<code>is_constructible_v&lt;extents_type, OtherExtents&gt;</code> is
<code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Preconditions:</em> <code>other.required_span_size()</code> is
representable as a value of type <code>index_type</code>
(<strong>[basic.fundamental]</strong>).</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Effects:</em> Direct-non-list-initializes
<em><code>the-extents</code></em> with <code>other.extents()</code>.</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> index_type required_span_size<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Returns:</em> <code>extent(0)</code> * (<code>extent(0)</code> +
1)/2. <i>[Note:</i> For example, a 5 x 5 packed matrix only stores 15
matrix elements. <i>– end note]</i></p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> <span class="op">...</span> Indices<span class="op">&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> index_type <span class="kw">operator</span><span class="op">()</span> <span class="op">(</span>Indices<span class="op">...</span> k<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Constraints</em>:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.1)</a></span>
<code>sizeof...(Indices)</code> equals
<code>extents_type::rank()</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.2)</a></span>
<code>(is_convertible_v&lt;Indices, index_Type&gt; &amp;&amp; ...)</code>
is <code>true</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.3)</a></span>
<code>(is_nothrow_constructible_v&lt;index_type, Indices&gt;)</code> is
<code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Preconditions:</em>
<code>extents_type::</code><em><code>index-cast</code></em><code>(k)</code>
is a multidimensional index in <em><code>the-extents</code></em>
(<strong>[mdspan.overview]</strong>).</p>
<p><span class="marginalizedparent"><a class="marginalized">13</a></span>
<em>Returns:</em> Let <code>N</code> equal <code>extent(0)</code>, let
<code>i</code> be the zeroth element of <code>k</code>, and let
<code>j</code> be the first element of <code>k</code>. Then:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(13.1)</a></span> If
<code>StorageOrder</code> is <code>column_major_t</code> and</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(13.1.1)</a></span>
if <code>Triangle</code> is <code>upper_triangle_t</code>, then
<code>i</code> + <code>j</code> * (<code>j</code> + 1)/2 if
<code>i</code> ≤ <code>j</code>, else <code>j</code> + <code>i</code> *
(<code>i</code> + 1)/2;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(13.1.2)</a></span>
else, if <code>Triangle</code> is <code>lower_triangle_t</code>, then
<code>i</code> + <code>N</code> * <code>j</code> - <code>j</code> *
(<code>j</code> + 1)/2 if <code>i</code> ≥ <code>j</code>, else
<code>j</code> + <code>N</code> * <code>i</code> - <code>i</code> *
(<code>i</code> + 1)/2;</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(13.2)</a></span>
else, if <code>StorageOrder</code> is <code>row_major_t</code> and</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(13.2.1)</a></span>
if <code>Triangle</code> is <code>upper_triangle_t</code>, then
<code>j</code> + <code>N</code> * <code>i</code> - <code>i</code> *
(<code>i</code> + 1)/2 if <code>i</code> ≤ <code>j</code>, else
<code>i</code> + <code>N</code> * <code>j</code> - <code>j</code> *
(<code>j</code> + 1)/2;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(13.2.2)</a></span>
else, if <code>Triangle</code> is <code>lower_triangle_t</code>, then
<code>j</code> + <code>i</code> * (<code>i</code> + 1)/2 if
<code>i</code> ≥ <code>j</code>, else <code>i</code> + <code>j</code> *
(<code>j</code> + 1)/2.</p></li>
</ul></li>
</ul>
<p><i>[Note:</i> An <code>mdspan</code> layout mapping must permit
access for all multidimensional indices in the cross product of the
extents, so the above definition cannot exclude indices outside the
matrix’s triangle. Instead, it interprets such indices as if the matrix
were symmetric. <i>– end note]</i></p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">operator</span><span class="op">==(</span><span class="kw">const</span> mapping<span class="op">&amp;</span>, <span class="kw">const</span> mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">14</a></span>
<em>Constraints:</em> <code>OtherExtents::rank()</code> equals
<code>rank()</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">15</a></span>
<em>Returns:</em> <code>true</code> if and only if for 0 ≤
<code>r</code> &lt; <code>rank()</code>, <code>m.extent(r)</code> equals
<code>extent(r)</code>.</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> index_type stride<span class="op">(</span>rank_type<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">16</a></span>
<em>Returns:</em> 1 if <code>extent(0)</code> is less than 2, else
0.</p>
<h2 data-number="16.5" id="scaled-in-place-transformation-linalg.scaled"><span class="header-section-number">16.5</span> Scaled in-place transformation
[linalg.scaled]<a href="#scaled-in-place-transformation-linalg.scaled" class="self-link"></a></h2>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The <code>scaled</code> function takes a value <code>alpha</code> and an
<code>mdspan</code> <code>x</code>, and returns a new read-only
<code>mdspan</code> with the same domain as <code>x</code>, that
represents the elementwise product of <code>alpha</code> with each
element of <code>x</code>.</p>
<p>[<em>Example:</em></p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="co">// z = alpha * x + y</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> z_equals_alpha_times_x_plus_y<span class="op">(</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, dextents<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">1</span><span class="op">&gt;&gt;</span> z,</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="dt">double</span> alpha,</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, dextents<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">1</span><span class="op">&gt;&gt;</span> x,</span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, dextents<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">1</span><span class="op">&gt;&gt;</span> y<span class="op">)</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>  add<span class="op">(</span>scaled<span class="op">(</span>alpha, x<span class="op">)</span>, y, y<span class="op">)</span>;</span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a><span class="co">// w = alpha * x + beta * y</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> w_equals_alpha_times_x_plus_beta_times_y<span class="op">(</span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, dextents<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">1</span><span class="op">&gt;&gt;</span> w,</span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="dt">double</span> alpha,</span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, dextents<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">1</span><span class="op">&gt;&gt;</span> x,</span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="dt">double</span> beta,</span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, dextents<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">1</span><span class="op">&gt;&gt;</span> y<span class="op">)</span></span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a>  add<span class="op">(</span>scaled<span class="op">(</span>alpha, x<span class="op">)</span>, scaled<span class="op">(</span>beta, y<span class="op">)</span>, w<span class="op">)</span>;</span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>–<em>end example</em>]</p>
<p><i>[Note:</i> An implementation could dispatch to a function in the
BLAS library, by noticing that the first argument has an
<code>accessor_scaled</code> <code>Accessor</code> type. It could use
this information to extract the appropriate run-time value(s) of the
relevant BLAS function arguments (e.g., <code>ALPHA</code> and/or
<code>BETA</code>), by calling
<code>accessor_scaled::scaling_factor</code>. <i>– end note]</i></p>
<h3 data-number="16.5.1" id="exposition-only-function-object-conj-if-needed-linalg.scaled.conj"><span class="header-section-number">16.5.1</span> Exposition-only function
object <em><code>conj-if-needed</code></em> [linalg.scaled.conj]<a href="#exposition-only-function-object-conj-if-needed-linalg.scaled.conj" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The name <em><code>conj-if-needed</code></em> denotes an exposition-only
function object. The expression
<em><code>conj-if-needed</code></em><code>(E)</code> for subexpression
<code>E</code> is expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>E</code>, if <code>T</code> is an arithmetic type;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
else, <code>conj(E)</code>, if that expression is valid with overload
resolution performed in a context that includes the declaration
<code>template&lt;class T&gt; T conj(const T&amp;) = delete;</code> and
does not include a declaration of
<code>linalg::</code><em><code>conj-if-needed</code></em>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
else, <code>E</code>.</p></li>
</ul>
<p><i>[Note:</i> The special case for arithmetic types preserves the
type of its argument, unlike <code>std::conj</code>. The
<code>conj(E)</code> case invokes <code>conj</code> via unqualified
lookup. The <code>E</code> case presumes that a type without a
<code>conj</code> function is noncomplex, so that the conjugate is the
identity. <i>– end note]</i></p>
<h3 data-number="16.5.2" id="exposition-only-class-templates-proxy-reference-base-and-proxy-reference-linalg.scaled.base"><span class="header-section-number">16.5.2</span> Exposition-only class
templates <em><code>proxy-reference-base</code></em> and
<em><code>proxy-reference</code></em> [linalg.scaled.base]<a href="#exposition-only-class-templates-proxy-reference-base-and-proxy-reference-linalg.scaled.base" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The exposition-only class <em><code>proxy-reference-base</code></em> is
a tag to identify whether a class is a specialization of either
<em><code>scaled-scalar</code></em>
<strong>[linalg.scaled.accessor_scaled]</strong> or
<em><code>conjugated-scalar</code></em>
<strong>[linalg.scaled.accessor_conjugated]</strong>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The exposition-only class template <em><code>proxy-reference</code></em>
is part of the implementation of <em><code>scaled-scalar</code></em>
<strong>[linalg.scaled.accessor_scaled]</strong> and
<em><code>conjugated-scalar</code></em>
<strong>[linalg.scaled.accessor_conjugated]</strong>.</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <em>proxy-reference-base</em> <span class="op">{}</span>; <span class="co">// exposition only</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Reference, <span class="kw">class</span> Value, <span class="kw">class</span> Derived<span class="op">&gt;</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <em>proxy-reference</em> <span class="op">:</span> <span class="kw">public</span> <em>proxy-reference-base</em> <span class="op">{</span> <span class="co">// exposition only</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> this_type <span class="op">=</span> <em>proxy-reference</em><span class="op">&lt;</span>Reference, Value, Derived<span class="op">&gt;</span>;</span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>  Reference reference_;</span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> reference_type <span class="op">=</span> Reference;</span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> value_type <span class="op">=</span> Value;</span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> derived_type <span class="op">=</span> Derived;</span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span> <em>proxy-reference</em><span class="op">(</span>Reference reference<span class="op">)</span> <span class="op">:</span> reference_<span class="op">(</span>reference<span class="op">)</span> <span class="op">{}</span></span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">operator</span> value_type<span class="op">()</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="kw">const</span> Derived<span class="op">&amp;&gt;(*</span><span class="kw">this</span><span class="op">).</span>to_value<span class="op">(</span>reference_<span class="op">)</span>;</span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-20"><a href="#cb18-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-21"><a href="#cb18-21" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">-(</span><span class="kw">const</span> derived_type<span class="op">&amp;</span> cs<span class="op">)</span></span>
<span id="cb18-22"><a href="#cb18-22" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-23"><a href="#cb18-23" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">-</span>value_type<span class="op">(</span>cs<span class="op">)</span>;</span>
<span id="cb18-24"><a href="#cb18-24" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-25"><a href="#cb18-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-26"><a href="#cb18-26" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Rhs, enable_if_t<span class="op">&lt;</span>is_base_of_v<span class="op">&lt;</span><em>proxy-reference-base</em>, Rhs<span class="op">&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span><span class="op">&gt;</span></span>
<span id="cb18-27"><a href="#cb18-27" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">+</span> <span class="op">(</span>derived_type lhs, Rhs rhs<span class="op">)</span></span>
<span id="cb18-28"><a href="#cb18-28" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-29"><a href="#cb18-29" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> <em>rhs-value-type</em> <span class="op">=</span> <span class="kw">typename</span> Rhs<span class="op">::</span>value_type; <span class="co">// exposition only</span></span>
<span id="cb18-30"><a href="#cb18-30" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> value_type<span class="op">(</span>lhs<span class="op">)</span> <span class="op">+</span> <em>rhs-value-type</em><span class="op">(</span>rhs<span class="op">)</span>;</span>
<span id="cb18-31"><a href="#cb18-31" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-32"><a href="#cb18-32" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Rhs, enable_if_t<span class="op">&lt;!</span> is_base_of_v<span class="op">&lt;</span><em>proxy-reference-base</em>, Rhs<span class="op">&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span><span class="op">&gt;</span></span>
<span id="cb18-33"><a href="#cb18-33" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">+</span> <span class="op">(</span>derived_type lhs, Rhs rhs<span class="op">)</span></span>
<span id="cb18-34"><a href="#cb18-34" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-35"><a href="#cb18-35" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> value_type<span class="op">(</span>lhs<span class="op">)</span> <span class="op">+</span> rhs;</span>
<span id="cb18-36"><a href="#cb18-36" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-37"><a href="#cb18-37" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Lhs, enable_if_t<span class="op">&lt;!</span> is_base_of_v<span class="op">&lt;</span><em>proxy-reference-base</em>, Lhs<span class="op">&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span><span class="op">&gt;</span></span>
<span id="cb18-38"><a href="#cb18-38" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">+</span> <span class="op">(</span>Lhs lhs, derived_type rhs<span class="op">)</span></span>
<span id="cb18-39"><a href="#cb18-39" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-40"><a href="#cb18-40" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> lhs <span class="op">+</span> value_type<span class="op">(</span>rhs<span class="op">)</span>;</span>
<span id="cb18-41"><a href="#cb18-41" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-42"><a href="#cb18-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-43"><a href="#cb18-43" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Rhs, enable_if_t<span class="op">&lt;</span>is_base_of_v<span class="op">&lt;</span><em>proxy-reference-base</em>, Rhs<span class="op">&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span><span class="op">&gt;</span></span>
<span id="cb18-44"><a href="#cb18-44" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">-</span> <span class="op">(</span>derived_type lhs, Rhs rhs<span class="op">)</span></span>
<span id="cb18-45"><a href="#cb18-45" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-46"><a href="#cb18-46" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> <em>rhs-value-type</em> <span class="op">=</span> <span class="kw">typename</span> Rhs<span class="op">::</span>value_type; <span class="co">// exposition only</span></span>
<span id="cb18-47"><a href="#cb18-47" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> value_type<span class="op">(</span>lhs<span class="op">)</span> <span class="op">-</span> <em>rhs-value-type</em><span class="op">(</span>rhs<span class="op">)</span>;</span>
<span id="cb18-48"><a href="#cb18-48" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-49"><a href="#cb18-49" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Rhs, enable_if_t<span class="op">&lt;!</span> is_base_of_v<span class="op">&lt;</span><em>proxy-reference-base</em>, Rhs<span class="op">&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span><span class="op">&gt;</span></span>
<span id="cb18-50"><a href="#cb18-50" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">-</span> <span class="op">(</span>derived_type lhs, Rhs rhs<span class="op">)</span></span>
<span id="cb18-51"><a href="#cb18-51" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-52"><a href="#cb18-52" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> value_type<span class="op">(</span>lhs<span class="op">)</span> <span class="op">-</span> rhs;</span>
<span id="cb18-53"><a href="#cb18-53" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-54"><a href="#cb18-54" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Lhs, enable_if_t<span class="op">&lt;!</span> is_base_of_v<span class="op">&lt;</span><em>proxy-reference-base</em>, Lhs<span class="op">&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span><span class="op">&gt;</span></span>
<span id="cb18-55"><a href="#cb18-55" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">-</span> <span class="op">(</span>Lhs lhs, derived_type rhs<span class="op">)</span></span>
<span id="cb18-56"><a href="#cb18-56" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-57"><a href="#cb18-57" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> lhs <span class="op">-</span> value_type<span class="op">(</span>rhs<span class="op">)</span>;</span>
<span id="cb18-58"><a href="#cb18-58" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-59"><a href="#cb18-59" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-60"><a href="#cb18-60" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Rhs, enable_if_t<span class="op">&lt;</span>is_base_of_v<span class="op">&lt;</span><em>proxy-reference-base</em>, Rhs<span class="op">&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span><span class="op">&gt;</span></span>
<span id="cb18-61"><a href="#cb18-61" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">*</span> <span class="op">(</span>derived_type lhs, Rhs rhs<span class="op">)</span></span>
<span id="cb18-62"><a href="#cb18-62" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-63"><a href="#cb18-63" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> <em>rhs-value-type</em> <span class="op">=</span> <span class="kw">typename</span> Rhs<span class="op">::</span>value_type; <span class="co">// exposition only</span></span>
<span id="cb18-64"><a href="#cb18-64" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> value_type<span class="op">(</span>lhs<span class="op">)</span> <span class="op">*</span> <em>rhs-value-type</em><span class="op">(</span>rhs<span class="op">)</span>;</span>
<span id="cb18-65"><a href="#cb18-65" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-66"><a href="#cb18-66" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Rhs, enable_if_t<span class="op">&lt;!</span> is_base_of_v<span class="op">&lt;</span><em>proxy-reference-base</em>, Rhs<span class="op">&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span><span class="op">&gt;</span></span>
<span id="cb18-67"><a href="#cb18-67" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">*</span> <span class="op">(</span>derived_type lhs, Rhs rhs<span class="op">)</span></span>
<span id="cb18-68"><a href="#cb18-68" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-69"><a href="#cb18-69" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> value_type<span class="op">(</span>lhs<span class="op">)</span> <span class="op">*</span> rhs;</span>
<span id="cb18-70"><a href="#cb18-70" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-71"><a href="#cb18-71" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Lhs, enable_if_t<span class="op">&lt;!</span> is_base_of_v<span class="op">&lt;</span><em>proxy-reference-base</em>, Lhs<span class="op">&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span><span class="op">&gt;</span></span>
<span id="cb18-72"><a href="#cb18-72" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">*</span> <span class="op">(</span>Lhs lhs, derived_type rhs<span class="op">)</span></span>
<span id="cb18-73"><a href="#cb18-73" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-74"><a href="#cb18-74" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> lhs <span class="op">*</span> value_type<span class="op">(</span>rhs<span class="op">)</span>;</span>
<span id="cb18-75"><a href="#cb18-75" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-76"><a href="#cb18-76" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-77"><a href="#cb18-77" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Rhs, enable_if_t<span class="op">&lt;</span>is_base_of_v<span class="op">&lt;</span><em>proxy-reference-base</em>, Rhs<span class="op">&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span><span class="op">&gt;</span></span>
<span id="cb18-78"><a href="#cb18-78" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">/</span> <span class="op">(</span>derived_type lhs, Rhs rhs<span class="op">)</span></span>
<span id="cb18-79"><a href="#cb18-79" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-80"><a href="#cb18-80" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> <em>rhs-value-type</em> <span class="op">=</span> <span class="kw">typename</span> Rhs<span class="op">::</span>value_type; <span class="co">// exposition only</span></span>
<span id="cb18-81"><a href="#cb18-81" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> value_type<span class="op">(</span>lhs<span class="op">)</span> <span class="op">/</span> <em>rhs-value-type</em><span class="op">(</span>rhs<span class="op">)</span>;</span>
<span id="cb18-82"><a href="#cb18-82" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-83"><a href="#cb18-83" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Rhs, enable_if_t<span class="op">&lt;!</span> is_base_of_v<span class="op">&lt;</span><em>proxy-reference-base</em>, Rhs<span class="op">&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span><span class="op">&gt;</span></span>
<span id="cb18-84"><a href="#cb18-84" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">/</span> <span class="op">(</span>derived_type lhs, Rhs rhs<span class="op">)</span></span>
<span id="cb18-85"><a href="#cb18-85" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-86"><a href="#cb18-86" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> value_type<span class="op">(</span>lhs<span class="op">)</span> <span class="op">/</span> rhs;</span>
<span id="cb18-87"><a href="#cb18-87" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-88"><a href="#cb18-88" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Lhs, enable_if_t<span class="op">&lt;!</span> is_base_of_v<span class="op">&lt;</span><em>proxy-reference-base</em>, Lhs<span class="op">&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span><span class="op">&gt;</span></span>
<span id="cb18-89"><a href="#cb18-89" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">/</span> <span class="op">(</span>Lhs lhs, derived_type rhs<span class="op">)</span></span>
<span id="cb18-90"><a href="#cb18-90" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb18-91"><a href="#cb18-91" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> lhs <span class="op">/</span> value_type<span class="op">(</span>rhs<span class="op">)</span>;</span>
<span id="cb18-92"><a href="#cb18-92" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-93"><a href="#cb18-93" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-94"><a href="#cb18-94" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> abs<span class="op">(</span><span class="kw">const</span> derived_type<span class="op">&amp;</span> x<span class="op">)</span>;</span>
<span id="cb18-95"><a href="#cb18-95" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-96"><a href="#cb18-96" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> real<span class="op">(</span><span class="kw">const</span> derived_type<span class="op">&amp;</span> x<span class="op">)</span>;</span>
<span id="cb18-97"><a href="#cb18-97" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-98"><a href="#cb18-98" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> imag<span class="op">(</span><span class="kw">const</span> derived_type<span class="op">&amp;</span> x<span class="op">)</span>;</span>
<span id="cb18-99"><a href="#cb18-99" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-100"><a href="#cb18-100" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> conj<span class="op">(</span><span class="kw">const</span> derived_type<span class="op">&amp;</span> x<span class="op">)</span>;</span>
<span id="cb18-101"><a href="#cb18-101" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> abs<span class="op">(</span><span class="kw">const</span> derived_type<span class="op">&amp;</span> x<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
The expression <code>abs(E)</code> for subexpression <code>E</code>
whose type is <code>derived_type</code> is expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
<code>value_type(static_cast&lt;const this_type&amp;&gt;(E))</code>, if
<code>value_type</code> is an unsigned integer;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
else,
<code>abs(value_type(static_cast&lt;const this_type&amp;&gt;(E)))</code>,
if that expression is valid, with overload resolution performed in a
context that includes the declaration
<code>template&lt;class T&gt; T abs(T) = delete;</code>. If the function
selected by overload resolution does not return the absolute value of
its input, the program is ill-formed, no diagnostic required.</p></li>
</ul>
<!-- TODO (mfh 2022/07/06) this lookup language will go into front matter. -->
<p><i>[Note:</i> This function exists because of
<code>vector_norm2</code> and <code>vector_abs_sum</code>.</p>
<p>The unsigned integer special case avoids an ambiguous lookup. The
other case invokes <code>abs</code> via unqualified lookup. <i>– end
note]</i></p>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> real<span class="op">(</span><span class="kw">const</span> derived_type<span class="op">&amp;</span> x<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
The expression <code>real(E)</code> for subexpression <code>E</code>
whose type is <code>derived_type</code> is expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<code>value_type(static_cast&lt;const this_type&amp;&gt;(E))</code>, if
<code>value_type</code> is an arithmetic type;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
else,
<code>real(value_type(static_cast&lt;const this_type&amp;&gt;(E)))</code>,
if that expression is valid, with overload resolution performed in a
context that includes the declaration
<code>template&lt;class T&gt; T real(T) = delete;</code>; if the
function selected by overload resolution does not return the absolute
value of its input, the program is ill-formed, no diagnostic
required;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span>
else,
<code>value_type(static_cast&lt;const this_type&amp;&gt;(E))</code>.</p></li>
</ul>
<p><i>[Note:</i> This function exists because of
<code>vector_abs_sum</code>.</p>
<p>The arithmetic type special case exists because
<code>std::real</code> returns a different type than its input for some
arithmetic types. All arithmetic types represent a noncomplex number.
Otherwise, if <code>real</code> can be found via unqualified lookup, it
is used. If not, then <code>value_type</code> is assumed to represent a
noncomplex number, for which the number’s real part is the same as the
number. <i>– end note]</i></p>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> imag<span class="op">(</span><span class="kw">const</span> derived_type<span class="op">&amp;</span> x<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
The expression <code>imag(E)</code> for subexpression <code>E</code>
whose type is <code>derived_type</code> is expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span>
<code>value_type{}</code>, if <code>value_type</code> is an arithmetic
type;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
else,
<code>imag(value_type(static_cast&lt;const this_type&amp;&gt;(E)))</code>,
if that expression is valid, with overload resolution performed in a
context that includes the declaration
<code>template&lt;class T&gt; T imag(T) = delete;</code>; if the
function selected by overload resolution does not return the absolute
value of its input, the program is ill-formed, no diagnostic
required;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.3)</a></span>
else, <code>value_type{}</code>.</p></li>
</ul>
<p><i>[Note:</i> This function exists because of
<code>vector_abs_sum</code>.</p>
<p>The arithmetic type special case exists because
<code>std::imag</code> returns a different type than its input for some
arithmetic types. All arithmetic types represent a noncomplex number.
Otherwise, if <code>imag</code> can be found via unqualified lookup, it
is used. If not, then <code>value_type</code> is assumed to represent a
noncomplex number, for which the number’s imaginary part is zero (which
is constructed by value-initializing <code>value_type</code>). <i>– end
note]</i></p>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">friend</span> <span class="kw">auto</span> conj<span class="op">(</span><span class="kw">const</span> derived_type<span class="op">&amp;</span> x<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>conj-if-needed</code></em><code>(x);</code>.</p>
<h3 data-number="16.5.3" id="exposition-only-class-template-scaled-scalar"><span class="header-section-number">16.5.3</span> Exposition-only class
template <em><code>scaled-scalar</code></em><a href="#exposition-only-class-template-scaled-scalar" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The exposition-only class template <em><code>scaled-scalar</code></em>
represents a read-only value, which is the product of a fixed value (the
“scaling factor”) and the value of a reference to an element of a
<code>mdspan</code>. <i>[Note:</i> The value is read only to avoid
confusion with the definition of “assigning to a scaled scalar.” <i>–
end note]</i> <em><code>scaled-scalar</code></em> is part of the
implementation of <code>accessor_scaled</code>
<strong>[linalg.scaled.accessor_scaled]</strong>.</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ScalingFactor, <span class="kw">class</span> ReferenceValue<span class="op">&gt;</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>scalable</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="kw">requires</span> <span class="op">{</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span> declval<span class="op">&lt;</span>ScalingFactor<span class="op">&gt;()</span> <span class="op">*</span> declval<span class="op">&lt;</span>ReferenceValue<span class="op">&gt;()</span> <span class="op">}</span>;</span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ScalingFactor, <span class="kw">class</span> Reference, <span class="kw">class</span> ReferenceValue<span class="op">&gt;</span></span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <em>scaled-scalar</em> <span class="op">:</span> <span class="co">// exposition only</span></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">public</span> <em>proxy-reference</em><span class="op">&lt;</span>Reference, ReferenceValue,</span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a>    <em>scaled-scalar</em><span class="op">&lt;</span>ScalingFactor, Reference, ReferenceValue<span class="op">&gt;&gt;</span></span>
<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb23-12"><a href="#cb23-12" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb23-13"><a href="#cb23-13" aria-hidden="true" tabindex="-1"></a>  ScalingFactor <em>scaling-factor</em>; <span class="co">// exposition only</span></span>
<span id="cb23-14"><a href="#cb23-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-15"><a href="#cb23-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em>my-type</em> <span class="op">=</span> <em>scaled-scalar</em><span class="op">&lt;</span>ScalingFactor, Reference, ReferenceValue<span class="op">&gt;</span>; <span class="co">// exposition only</span></span>
<span id="cb23-16"><a href="#cb23-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em>base-type</em> <span class="op">=</span> <em>proxy-reference</em><span class="op">&lt;</span>Reference, ReferenceValue, <em>my-type</em><span class="op">&gt;</span>; <span class="co">// exposition only</span></span>
<span id="cb23-17"><a href="#cb23-17" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb23-18"><a href="#cb23-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">explicit</span> <em>scaled-scalar</em><span class="op">(</span><span class="kw">const</span> ScalingFactor<span class="op">&amp;</span> scaling_factor, <span class="kw">const</span> Reference<span class="op">&amp;</span> reference<span class="op">)</span>;</span>
<span id="cb23-19"><a href="#cb23-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-20"><a href="#cb23-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> value_type <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span><em>scaling-factor</em> <span class="op">*</span> ReferenceValue<span class="op">(</span>declval<span class="op">&lt;</span>Reference<span class="op">&gt;()))</span>;</span>
<span id="cb23-21"><a href="#cb23-21" aria-hidden="true" tabindex="-1"></a>  value_type to_value<span class="op">(</span>Reference reference<span class="op">)</span> <span class="kw">const</span>;</span>
<span id="cb23-22"><a href="#cb23-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><i>[Note:</i> The point of the <code>ReferenceValue</code> template
parameter is so that the input of <code>to_value</code> can be cast to a
value immediately, before any transformations are applied. This ensures
the original order of operations, as if computing nonlazily. It also
makes fewer requirements of the reference type. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<em><code>scalable</code></em><code>&lt;ScalingFactor, ReferenceValue&gt;</code>,
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>value_type</code> is a complete object type that is neither an
abstract class type nor an array type.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<code>ScalingFactor</code> models <code>semiregular</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<code>Reference</code> models <code>copy_constructible</code>.</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">explicit</span> scaled_scalar<span class="op">(</span><span class="kw">const</span> ScalingFactor<span class="op">&amp;</span> scaling_factor, <span class="kw">const</span> Reference<span class="op">&amp;</span> reference<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span>
Direct non-list-initializes <code>static_cast&lt;</code>
<em><code>base-type</code></em> <code>&amp;&gt;(*this)</code> with
<code>reference</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
direct non-list-initializes <em><code>scaling-factor</code></em> with
<code>scaling_factor</code>.</p></li>
</ul>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a>value_type to_value<span class="op">(</span>Reference reference<span class="op">)</span> <span class="kw">const</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>scaling-factor</code></em>
<code>* ReferenceValue(reference);</code>.</p>
<h3 data-number="16.5.4" id="class-template-accessor_scaled-linalg.scaled.accessor_scaled"><span class="header-section-number">16.5.4</span> Class template
<code>accessor_scaled</code> [linalg.scaled.accessor_scaled]<a href="#class-template-accessor_scaled-linalg.scaled.accessor_scaled" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The class template <code>accessor_scaled</code> is an
<code>mdspan</code> accessor policy whose reference type represents the
product of a fixed value (the “scaling factor”) and its nested
<code>mdspan</code> accessor’s reference. It is part of the
implementation of <code>scaled</code>
<strong>[linalg.scaled.scaled]</strong>.</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ScalingFactor,</span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> accessor_scaled <span class="op">{</span></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> reference <span class="op">=</span> scaled_scalar<span class="op">&lt;</span>ScalingFactor,</span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">typename</span> Accessor<span class="op">::</span>reference,</span>
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">typename</span> Accessor<span class="op">::</span>element_type<span class="op">&gt;</span>;</span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> element_type <span class="op">=</span> add_const_t<span class="op">&lt;</span><span class="kw">typename</span> reference<span class="op">::</span>value_type<span class="op">&gt;</span>;</span>
<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> Accessor<span class="op">::</span>data_handle_type;</span>
<span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> offset_policy <span class="op">=</span> accessor_scaled<span class="op">&lt;</span>ScalingFactor, Accessor<span class="op">::</span>offset_policy<span class="op">&gt;</span>;</span>
<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> accessor_scaled<span class="op">(</span><span class="kw">const</span> ScalingFactor<span class="op">&amp;</span> s, <span class="kw">const</span> Accessor<span class="op">&amp;</span> a<span class="op">)</span>;</span>
<span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> reference access<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-16"><a href="#cb26-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> offset_policy<span class="op">::</span>data_handle_type offset<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-17"><a href="#cb26-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-18"><a href="#cb26-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> ScalingFactor scaling_factor<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb26-19"><a href="#cb26-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-20"><a href="#cb26-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> Accessor nested_accessor<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb26-21"><a href="#cb26-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-22"><a href="#cb26-22" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb26-23"><a href="#cb26-23" aria-hidden="true" tabindex="-1"></a>  ScalingFactor <em>scaling-factor</em>; <span class="co">// exposition only</span></span>
<span id="cb26-24"><a href="#cb26-24" aria-hidden="true" tabindex="-1"></a>  Accessor <em>nested-accessor</em>; <span class="co">// exposition only</span></span>
<span id="cb26-25"><a href="#cb26-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>is_copy_constructible_v&lt;typename Accessor::reference&gt;</code>
is <code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>ScalingFactor</code> models <code>semiregular</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<code>Accessor</code> meets the accessor policy requirements
<strong>[mdspan.accessor.reqmts]</strong>.</p></li>
</ul>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> accessor_scaled<span class="op">(</span><span class="kw">const</span> ScalingFactor<span class="op">&amp;</span> s, <span class="kw">const</span> Accessor<span class="op">&amp;</span> a<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
Direct non-list-initializes <em><code>scaling-factor</code></em> with
<code>s</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
direct non-list-initializes <em><code>nested-accessor</code></em> with
<code>a</code>.</p></li>
</ul>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> reference access<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em> Equivalent to
<code>return reference(</code><em><code>scaling-factor</code></em><code>,</code>
<em><code>nested-accessor</code></em><code>.access(p, i));</code>.</p>
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> offset_policy<span class="op">::</span>data_handle_type</span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a>offset<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-accessor</code></em><code>.offset(p, i);</code>.</p>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> ScalingFactor scaling_factor<span class="op">()</span> <span class="kw">const</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>scaling-factor</code></em><code>;</code>.</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> Accessor nested_accessor<span class="op">()</span> <span class="kw">const</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-accessor</code></em><code>;</code>.</p>
<h3 data-number="16.5.5" id="scaled-linalg.scaled.scaled"><span class="header-section-number">16.5.5</span> <code>scaled</code>
[linalg.scaled.scaled]<a href="#scaled-linalg.scaled.scaled" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The <code>scaled</code> function takes a scaling factor
<code>alpha</code> and an <code>mdspan</code> <code>x</code>, and
returns a new read-only <code>mdspan</code> with the same domain as
<code>x</code>, that represents the elementwise product of
<code>alpha</code> with each element of <code>x</code>.</p>
<p><i>[Note:</i> Terms in this product will not be reordered. <i>– end
note]</i></p>
<div class="sourceCode" id="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ScalingFactor,</span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> ElementType,</span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Extents,</span>
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Layout,</span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> scaled<span class="op">(</span></span>
<span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a>  ScalingFactor scaling_factor,</span>
<span id="cb32-8"><a href="#cb32-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> mdspan<span class="op">&lt;</span>ElementType, Extents, Layout, Accessor<span class="op">&gt;&amp;</span> x<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> Equivalent to
<code>return mdspan{x.data(), x.mapping(), accessor_scaled{alpha, x.accessor()}};</code>.</p>
<p><i>[Note:</i> The elements of the returned <code>mdspan</code> are
read only.</p>
<p>Nested <code>scaled</code> expressions remain nested. An expression
such as <code>scaled(alpha, scaled(beta, x))</code> would not be
transformed into <code>scaled(alpha * beta, x)</code>. This is because
such transformations would change at least the order of operations, and
possibly also the result type. For example, if <code>x</code> is a
rank-1 <code>mdspan</code> whose <code>value_type</code> is
<code>double</code>, and if <code>sizeof(int)</code> is 4 and
<code>double</code> is IEEE 754 binary64, then
<code>scaled(1 &lt;&lt; 20, scaled(1 &lt;&lt; 20, x))</code> does not
overflow <code>int</code>, but
<code>scaled((1 &lt;&lt; 20) * (1 &lt;&lt; 20), x)</code> would overflow
<code>int</code>. <i>– end note]</i></p>
<p>[<em>Example:</em></p>
<div class="sourceCode" id="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> test_scaled<span class="op">(</span>mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">10</span><span class="op">&gt;&gt;</span> x<span class="op">)</span></span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> x_scaled <span class="op">=</span> scaled<span class="op">(</span><span class="fl">5.0</span>, x<span class="op">)</span>;</span>
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> x<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span>x_scaled<span class="op">[</span>i<span class="op">]</span> <span class="op">==</span> <span class="fl">5.0</span> <span class="op">*</span> x<span class="op">[</span>i<span class="op">])</span>;</span>
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>–<em>end example</em>]</p>
<h2 data-number="16.6" id="conjugated-in-place-transformation-linalg.conj"><span class="header-section-number">16.6</span> Conjugated in-place
transformation [linalg.conj]<a href="#conjugated-in-place-transformation-linalg.conj" class="self-link"></a></h2>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The <code>conjugated</code> function takes an <code>mdspan</code>
<code>x</code>, and returns a new read-only <code>mdspan</code>
<code>y</code> with the same domain as <code>x</code>, whose elements
are the complex conjugates of the corresponding elements of
<code>x</code>.</p>
<p><i>[Note:</i> An implementation could dispatch to a function in the
BLAS library, by noticing that the <code>Accessor</code> type of an
<code>mdspan</code> input has type <code>accessor_conjugate</code>, and
that its nested <code>Accessor</code> type is compatible with the BLAS
library. If so, it could set the corresponding <code>TRANS*</code> BLAS
function argument accordingly and call the BLAS function. <i>– end
note]</i></p>
<h3 data-number="16.6.1" id="exposition-only-class-template-conjugated-scalar"><span class="header-section-number">16.6.1</span> Exposition-only class
template <em><code>conjugated-scalar</code></em><a href="#exposition-only-class-template-conjugated-scalar" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The exposition-only class template
<em><code>conjugated-scalar</code></em> represents a read-only value,
which is the complex conjugate of the value of a reference to an element
of an <code>mdspan</code>. <i>[Note:</i> The value is read only to avoid
confusion with the definition of “assigning to the conjugate of a
scalar.” <i>– end note]</i> <em><code>conjugated-scalar</code></em> is
part of the implementation of <code>accessor_conjugate</code>
<strong>[linalg.conj.accessor_conjugate]</strong>.</p>
<div class="sourceCode" id="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ReferenceValue<span class="op">&gt;</span></span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>conjugatable</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a><span class="kw">requires</span> <span class="op">{</span></span>
<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span> <em>conj-if-needed</em><span class="op">(</span>declval<span class="op">&lt;</span>ReferenceValue<span class="op">&gt;())</span> <span class="op">}</span> <span class="op">-&gt;</span> same_as<span class="op">&lt;</span>ReferenceValue<span class="op">&gt;</span>;</span>
<span id="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-7"><a href="#cb34-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Reference, <em>conjugatable</em> ReferenceValue<span class="op">&gt;</span></span>
<span id="cb34-8"><a href="#cb34-8" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <em>conjugated-scalar</em> <span class="op">:</span> <span class="co">// exposition only</span></span>
<span id="cb34-9"><a href="#cb34-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">public</span> <em>proxy-reference</em><span class="op">&lt;</span>Reference, ReferenceValue, <em>conjugated-scalar</em><span class="op">&lt;</span>Reference, ReferenceValue<span class="op">&gt;&gt;</span></span>
<span id="cb34-10"><a href="#cb34-10" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb34-11"><a href="#cb34-11" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb34-12"><a href="#cb34-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em>my-type</em> <span class="op">=</span> <em>conjugated-scalar</em><span class="op">&lt;</span>Reference, ReferenceValue<span class="op">&gt;</span>; <span class="co">// exposition only</span></span>
<span id="cb34-13"><a href="#cb34-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em>base-type</em> <span class="op">=</span> <em>proxy-reference</em><span class="op">&lt;</span>Reference, ReferenceValue, <em>my-type</em><span class="op">&gt;</span>; <span class="co">// exposition only</span></span>
<span id="cb34-14"><a href="#cb34-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-15"><a href="#cb34-15" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb34-16"><a href="#cb34-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span> <em>conjugated-scalar</em><span class="op">(</span>Reference reference<span class="op">)</span>;</span>
<span id="cb34-17"><a href="#cb34-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-18"><a href="#cb34-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> value_type <span class="op">=</span> <span class="co">/* see below */</span>;</span>
<span id="cb34-19"><a href="#cb34-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">static</span> <span class="kw">auto</span> to_value<span class="op">(</span>Reference reference<span class="op">)</span>;</span>
<span id="cb34-20"><a href="#cb34-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<code>Reference</code> models <code>copy_constructible</code>.</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> value_type <span class="op">=</span> <span class="co">/* see below */</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<code>value_type</code> names the type
<code>decltype(</code><em><code>conj-if-needed</code></em><code>(ReferenceValue(declval&lt;Reference&gt;())))</code>.</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span> <em>conjugated-scalar</em><span class="op">(</span>Reference reference<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em> Initializes <em><code>base-type</code></em> with
<code>reference</code>.</p>
<div class="sourceCode" id="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">static</span> <span class="kw">auto</span> to_value<span class="op">(</span>Reference value_type<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Preconditions:</em> This function may be invoked arbitrarily many
times.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Effects:</em> Equivalent to
<code>return</code><em><code>conj-if-needed</code></em><code>(ReferenceValue(reference));</code>.</p>
<h3 data-number="16.6.2" id="class-template-accessor_conjugate-linalg.conj.accessor_conjugate"><span class="header-section-number">16.6.2</span> Class template
<code>accessor_conjugate</code> [linalg.conj.accessor_conjugate]<a href="#class-template-accessor_conjugate-linalg.conj.accessor_conjugate" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The class template <code>accessor_conjugate</code> is an
<code>mdspan</code> accessor policy whose reference type represents the
complex conjugate of its nested <code>mdspan</code> accessor’s
reference. It is part of the implementation of <code>conjugated</code>
<strong>[linalg.conj.conjugated]</strong>.</p>
<div class="sourceCode" id="cb38"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> accessor_conjugate <span class="op">{</span></span>
<span id="cb38-3"><a href="#cb38-3" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb38-4"><a href="#cb38-4" aria-hidden="true" tabindex="-1"></a>  Accessor <em>nested-accessor</em>; <span class="co">// exposition only</span></span>
<span id="cb38-5"><a href="#cb38-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-6"><a href="#cb38-6" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb38-7"><a href="#cb38-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> reference     <span class="op">=</span> <span class="co">/* see below */</span>;</span>
<span id="cb38-8"><a href="#cb38-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> element_type  <span class="op">=</span> <span class="co">/* see below */</span>;</span>
<span id="cb38-9"><a href="#cb38-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> <span class="kw">typename</span> Accessor<span class="op">::</span>data_handle_type;</span>
<span id="cb38-10"><a href="#cb38-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> offset_policy <span class="op">=</span> <span class="co">/* see below */</span>;</span>
<span id="cb38-11"><a href="#cb38-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-12"><a href="#cb38-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> accessor_conjugate<span class="op">(</span>Accessor a<span class="op">)</span>;</span>
<span id="cb38-13"><a href="#cb38-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-14"><a href="#cb38-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> reference access<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb38-15"><a href="#cb38-15" aria-hidden="true" tabindex="-1"></a>    <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span>reference<span class="op">(</span><em>nested-accessor</em><span class="op">.</span>access<span class="op">(</span>p, i<span class="op">))))</span>;</span>
<span id="cb38-16"><a href="#cb38-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-17"><a href="#cb38-17" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">typename</span> offset_policy<span class="op">::</span>data_handle_type</span>
<span id="cb38-18"><a href="#cb38-18" aria-hidden="true" tabindex="-1"></a>    offset<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb38-19"><a href="#cb38-19" aria-hidden="true" tabindex="-1"></a>      <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-accessor</em><span class="op">.</span>offset<span class="op">(</span>p, i<span class="op">)))</span>;</span>
<span id="cb38-20"><a href="#cb38-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-21"><a href="#cb38-21" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> Accessor nested_accessor<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb38-22"><a href="#cb38-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<code>Accessor</code> meets the <code>mdspan</code> accessor policy
requirements <strong>[mdspan.accessor.reqmts]</strong>.</p>
<div class="sourceCode" id="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> reference <span class="op">=</span> <span class="co">/* see below */</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
This names</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
<code>typename Accessor::reference</code>, if
<code>remove_cv_t&lt;typename Accessor::element_type&gt;</code> is an
arithmetic type;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
otherwise,
<em><code>conjugated-scalar</code></em><code>&lt;typename Accessor::reference, remove_cv_t&lt;typename Accessor::element_type&gt;&gt;</code>.</p></li>
</ul>
<div class="sourceCode" id="cb40"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> element_type <span class="op">=</span> <span class="co">/* see below */</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
Let the exposition-only type <code>pre-const-element-type</code>
name</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<code>typename Accessor::element_type</code>, if
<code>remove_cv&lt;typename Accessor::element_type&gt;</code> is an
arithmetic type;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
otherwise, <code>reference::value_type</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
Then, <code>element_type</code> names
<code>add_const_t&lt;</code><em><code>pre-const-element-type</code></em><code>&gt;</code>.</p>
<p><i>[Note:</i> <code>accessor_conjugate</code> provides read-only
access. <i>– end note]</i></p>
<div class="sourceCode" id="cb41"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> offset_policy <span class="op">=</span> <span class="co">/* see below */</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
This names</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span>
<code>typename Accessor::offset_policy</code>, if
<code>remove_cv_t&lt;typename Accessor::element_type&gt;</code> is an
arithmetic type;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span>
otherwise,
<code>accessor_conjugate&lt;typename Accessor::offset_policy&gt;</code>.</p></li>
</ul>
<div class="sourceCode" id="cb42"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> accessor_conjugate<span class="op">(</span>Accessor a<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Effects:</em> Direct non-list-initializes
<em><code>nested-accessor</code></em> with <code>a</code>.</p>
<div class="sourceCode" id="cb43"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> reference access<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span>reference<span class="op">(</span><em>nested-accessor</em><span class="op">.</span>access<span class="op">(</span>p, i<span class="op">))))</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Effects:</em> Equivalent to
<code>return reference(</code><em><code>nested-accessor</code></em><code>.access(p, i));</code>.</p>
<div class="sourceCode" id="cb44"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">typename</span> offset_policy<span class="op">::</span>data_handle_type</span>
<span id="cb44-2"><a href="#cb44-2" aria-hidden="true" tabindex="-1"></a>  offset<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb44-3"><a href="#cb44-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-accessor</em><span class="op">.</span>offset<span class="op">(</span>p, i<span class="op">)))</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-accessor</code></em><code>.offset(p, i);</code>.</p>
<div class="sourceCode" id="cb45"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb45-1"><a href="#cb45-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> Accessor nested_accessor<span class="op">()</span> <span class="kw">const</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-accessor</code></em><code>;</code>.</p>
<h3 data-number="16.6.3" id="conjugated-linalg.conj.conjugated"><span class="header-section-number">16.6.3</span> <code>conjugated</code>
[linalg.conj.conjugated]<a href="#conjugated-linalg.conj.conjugated" class="self-link"></a></h3>
<div class="sourceCode" id="cb46"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb46-1"><a href="#cb46-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType,</span>
<span id="cb46-2"><a href="#cb46-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Extents,</span>
<span id="cb46-3"><a href="#cb46-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Layout,</span>
<span id="cb46-4"><a href="#cb46-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb46-5"><a href="#cb46-5" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> conjugated<span class="op">(</span></span>
<span id="cb46-6"><a href="#cb46-6" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span>ElementType, Extents, Layout, Accessor<span class="op">&gt;</span> a<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Let <code>R</code> name the type
<code>mdspan&lt;ReturnElementType, Extents, Layout, ReturnAccessor&gt;</code>,
where</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>ReturnElementType</code> is</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1.1)</a></span> if
<code>Accessor</code> is
<code>accessor_conjugate&lt;NestedAccessor&gt;</code> for some
<code>NestedAccessor</code>, then
<code>typename NestedAccessor::element_type</code> <i>[Note:</i>
conjugation is self-annihilating <i>– end note]</i>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1.2)</a></span>
else if <code>remove_cv_t&lt;ElementType&gt;</code> is an arithmetic
type, then <code>ElementType</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1.3)</a></span>
else
<code>accessor_conjugate&lt;Accessor&gt;::element_type</code>;</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> and
<code>ReturnAccessor</code> is:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2.1)</a></span> if
<code>Accessor</code> is
<code>accessor_conjugate&lt;NestedAccessor&gt;</code> for some
<code>NestedAccessor</code>, then <code>NestedAccessor</code>
<i>[Note:</i> conjugation is self-annihilating <i>– end
note]</i>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2.2)</a></span>
else if <code>remove_cv_t&lt;ElementType&gt;</code> is an arithmetic
type, then <code>Accessor</code> <i>[Note:</i> this reduces nesting in
cases where conjugation is known to be the identity <i>– end
note]</i>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2.3)</a></span>
else <code>accessor_conjugate&lt;Accessor&gt;</code>.</p></li>
</ul></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> If
<code>Accessor</code> is
<code>accessor_conjugate&lt;NestedAccessor&gt;</code>, then equivalent
to
<code>return R(a.data(), a.mapping(), a.nested_accessor());</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span> else
if <code>remove_cv_t&lt;ElementType&gt;</code> is an arithmetic type,
then equivalent to
<code>return R(a.data(), a.mapping(), a.accessor());</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
else, equivalent to
<code>return R(a.data(), a.mapping(), ReturnAccessor(a.accessor()));</code>;</p></li>
</ul>
<p><i>[Note:</i> The elements of the returned <code>mdspan</code> are
read only. <i>– end note]</i>;</p>
<p>[<em>Example:</em></p>
<div class="sourceCode" id="cb47"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb47-1"><a href="#cb47-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> test_conjugated_complex<span class="op">(</span></span>
<span id="cb47-2"><a href="#cb47-2" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span>complex<span class="op">&lt;</span><span class="dt">double</span><span class="op">&gt;</span>, extents<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">10</span><span class="op">&gt;&gt;</span> a<span class="op">)</span></span>
<span id="cb47-3"><a href="#cb47-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb47-4"><a href="#cb47-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> a_conj <span class="op">=</span> conjugated<span class="op">(</span>a<span class="op">)</span>;</span>
<span id="cb47-5"><a href="#cb47-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> a<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb47-6"><a href="#cb47-6" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span>a_conj<span class="op">[</span>i<span class="op">]</span> <span class="op">==</span> conj<span class="op">(</span>a<span class="op">[</span>i<span class="op">])</span>;</span>
<span id="cb47-7"><a href="#cb47-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb47-8"><a href="#cb47-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> a_conj_conj <span class="op">=</span> conjugated<span class="op">(</span>a_conj<span class="op">)</span>;</span>
<span id="cb47-9"><a href="#cb47-9" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> a<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb47-10"><a href="#cb47-10" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span>a_conj_conj<span class="op">[</span>i<span class="op">]</span> <span class="op">==</span> a<span class="op">[</span>i<span class="op">])</span>;</span>
<span id="cb47-11"><a href="#cb47-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb47-12"><a href="#cb47-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb47-13"><a href="#cb47-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-14"><a href="#cb47-14" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> test_conjugated_real<span class="op">(</span></span>
<span id="cb47-15"><a href="#cb47-15" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">10</span><span class="op">&gt;&gt;</span> a<span class="op">)</span></span>
<span id="cb47-16"><a href="#cb47-16" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb47-17"><a href="#cb47-17" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> a_conj <span class="op">=</span> conjugated<span class="op">(</span>a<span class="op">)</span>;</span>
<span id="cb47-18"><a href="#cb47-18" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> a<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb47-19"><a href="#cb47-19" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span>a_conj<span class="op">[</span>i<span class="op">]</span> <span class="op">==</span> a<span class="op">[</span>i<span class="op">])</span>;</span>
<span id="cb47-20"><a href="#cb47-20" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb47-21"><a href="#cb47-21" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> a_conj_conj <span class="op">=</span> conjugated<span class="op">(</span>a_conj<span class="op">)</span>;</span>
<span id="cb47-22"><a href="#cb47-22" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> a<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb47-23"><a href="#cb47-23" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span>a_conj_conj<span class="op">[</span>i<span class="op">]</span> <span class="op">==</span> a<span class="op">[</span>i<span class="op">])</span>;</span>
<span id="cb47-24"><a href="#cb47-24" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb47-25"><a href="#cb47-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>–<em>end example</em>]</p>
<h2 data-number="16.7" id="transpose-in-place-transformation-linalg.transp"><span class="header-section-number">16.7</span> Transpose in-place
transformation [linalg.transp]<a href="#transpose-in-place-transformation-linalg.transp" class="self-link"></a></h2>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<code>layout_transpose</code> is an <code>mdspan</code> layout mapping
policy that swaps the rightmost two indices, extents, and strides (if
applicable) of any unique <code>mdspan</code> layout mapping policy.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The <code>transposed</code> function takes an <code>mdspan</code>
representing a matrix, and returns a new read-only <code>mdspan</code>
representing the transpose of the input matrix.</p>
<h3 data-number="16.7.1" id="layout_transpose-linalg.transp.layout_transpose"><span class="header-section-number">16.7.1</span>
<code>layout_transpose</code> [linalg.transp.layout_transpose]<a href="#layout_transpose-linalg.transp.layout_transpose" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<code>layout_transpose</code> is an <code>mdspan</code> layout mapping
policy that swaps the rightmost two indices, extents, and strides (if
applicable) of any unique <code>mdspan</code> layout mapping policy.</p>
<div class="sourceCode" id="cb48"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb48-1"><a href="#cb48-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> InputExtents<span class="op">&gt;</span></span>
<span id="cb48-2"><a href="#cb48-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <em>transpose-extents-t</em> <span class="op">=</span> <span class="co">/* see below */</span>; <span class="co">// exposition only</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
For <code>InputExtents</code> a specialization of <code>extents</code>,
<em><code>transpose-extents-t</code></em><code>&lt;InputExtents&gt;</code>
names the <code>extents</code> type <code>OutputExtents</code> such
that</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>InputExtents::static_extent(InputExtents::rank()-1)</code> equals
<code>OutputExtents::static_extent(OutputExtents::rank()-2)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>InputExtents::static_extent(InputExtents::rank()-2)</code> equals
<code>OutputExtents::static_extent(OutputExtents::rank()-1)</code>,
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<code>InputExtents::static_extent(r)</code> equals
<code>OutputExtents::static_extent(r)</code> for 0 ≤ <code>r</code> &lt;
<code>InputExtents::rank()-2</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Preconditions:</em> <code>InputExtents</code> is a specialization of
<code>extents</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Constraints:</em> <code>InputExtents::rank()</code> equals 2.</p>
<div class="sourceCode" id="cb49"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb49-1"><a href="#cb49-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> InputExtents<span class="op">&gt;</span></span>
<span id="cb49-2"><a href="#cb49-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <em>transpose-extents-t</em><span class="op">&lt;</span>InputExtents<span class="op">&gt;</span></span>
<span id="cb49-3"><a href="#cb49-3" aria-hidden="true" tabindex="-1"></a><em>transpose-extents</em><span class="op">(</span><span class="kw">const</span> InputExtents<span class="op">&amp;</span> in<span class="op">)</span>; <span class="co">// exposition only</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Constraints:</em> <code>InputExtents::rank()</code> equals 2.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Returns:</em> An <code>extents</code> object <code>out</code> such
that</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span>
<code>out.extent(in.rank()-1)</code> equals
<code>in.extent(in.rank()-2)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span>
<code>out.extent(in.rank()-2)</code> equals
<code>in.extent(in.rank()-1)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.3)</a></span>
<code>out.extent(r)</code> equals <code>in.extent(r)</code> for 0 ≤
<code>r</code> &lt; <code>in.rank()-2</code>.</p></li>
</ul>
<div class="sourceCode" id="cb50"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb50-1"><a href="#cb50-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Layout<span class="op">&gt;</span></span>
<span id="cb50-2"><a href="#cb50-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> layout_transpose <span class="op">{</span></span>
<span id="cb50-3"><a href="#cb50-3" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb50-4"><a href="#cb50-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb50-5"><a href="#cb50-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> mapping <span class="op">{</span></span>
<span id="cb50-6"><a href="#cb50-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">private</span><span class="op">:</span></span>
<span id="cb50-7"><a href="#cb50-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> <em>nested-mapping-type</em> <span class="op">=</span></span>
<span id="cb50-8"><a href="#cb50-8" aria-hidden="true" tabindex="-1"></a>      <span class="kw">typename</span> Layout<span class="op">::</span><span class="kw">template</span> mapping<span class="op">&lt;</span></span>
<span id="cb50-9"><a href="#cb50-9" aria-hidden="true" tabindex="-1"></a>        <em>transpose-extents-t</em><span class="op">&lt;</span>Extents<span class="op">&gt;&gt;</span>; <span class="co">// exposition only</span></span>
<span id="cb50-10"><a href="#cb50-10" aria-hidden="true" tabindex="-1"></a>    <em>nested-mapping-type</em> <em>nested-mapping</em>; <span class="co">// exposition only</span></span>
<span id="cb50-11"><a href="#cb50-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-12"><a href="#cb50-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">public</span><span class="op">:</span></span>
<span id="cb50-13"><a href="#cb50-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> extents_type <span class="op">=</span> Extents;</span>
<span id="cb50-14"><a href="#cb50-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> size_type <span class="op">=</span> <span class="kw">typename</span> extents_type<span class="op">::</span>size_type;</span>
<span id="cb50-15"><a href="#cb50-15" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> layout_type <span class="op">=</span> layout_transpose;</span>
<span id="cb50-16"><a href="#cb50-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-17"><a href="#cb50-17" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">explicit</span> mapping<span class="op">(</span><span class="kw">const</span> <em>nested-mapping-type</em><span class="op">&amp;</span> map<span class="op">)</span>;</span>
<span id="cb50-18"><a href="#cb50-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-19"><a href="#cb50-19" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> extents_type extents<span class="op">()</span> <span class="kw">const</span></span>
<span id="cb50-20"><a href="#cb50-20" aria-hidden="true" tabindex="-1"></a>      <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">.</span>extents<span class="op">()))</span>;</span>
<span id="cb50-21"><a href="#cb50-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-22"><a href="#cb50-22" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> size_type required_span_size<span class="op">()</span> <span class="kw">const</span></span>
<span id="cb50-23"><a href="#cb50-23" aria-hidden="true" tabindex="-1"></a>      <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">.</span>required_span_size<span class="op">()))</span>;</span>
<span id="cb50-24"><a href="#cb50-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-25"><a href="#cb50-25" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Indices<span class="op">&gt;</span></span>
<span id="cb50-26"><a href="#cb50-26" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> size_type <span class="kw">operator</span><span class="op">()(</span>Indices<span class="op">...</span> indices<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb50-27"><a href="#cb50-27" aria-hidden="true" tabindex="-1"></a>        <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">(</span>indices<span class="op">...)))</span>;</span>
<span id="cb50-28"><a href="#cb50-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-29"><a href="#cb50-29" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <em>nested-mapping-type</em> nested_mapping<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb50-30"><a href="#cb50-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-31"><a href="#cb50-31" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_unique<span class="op">()</span>;</span>
<span id="cb50-32"><a href="#cb50-32" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_contiguous<span class="op">()</span>;</span>
<span id="cb50-33"><a href="#cb50-33" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_strided<span class="op">()</span>;</span>
<span id="cb50-34"><a href="#cb50-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-35"><a href="#cb50-35" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> is_unique<span class="op">()</span> <span class="kw">const</span></span>
<span id="cb50-36"><a href="#cb50-36" aria-hidden="true" tabindex="-1"></a>      <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">.</span>is_unique<span class="op">()))</span>;</span>
<span id="cb50-37"><a href="#cb50-37" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> is_contiguous<span class="op">()</span> <span class="kw">const</span></span>
<span id="cb50-38"><a href="#cb50-38" aria-hidden="true" tabindex="-1"></a>      <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">.</span>is_contiguous<span class="op">()))</span>;</span>
<span id="cb50-39"><a href="#cb50-39" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> is_strided<span class="op">()</span> <span class="kw">const</span></span>
<span id="cb50-40"><a href="#cb50-40" aria-hidden="true" tabindex="-1"></a>      <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">.</span>is_strided<span class="op">()))</span>;</span>
<span id="cb50-41"><a href="#cb50-41" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-42"><a href="#cb50-42" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> size_type stride<span class="op">(</span><span class="dt">size_t</span> r<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb50-43"><a href="#cb50-43" aria-hidden="true" tabindex="-1"></a>      <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">.</span>stride<span class="op">(</span>r<span class="op">)))</span>;</span>
<span id="cb50-44"><a href="#cb50-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-45"><a href="#cb50-45" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb50-46"><a href="#cb50-46" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span></span>
<span id="cb50-47"><a href="#cb50-47" aria-hidden="true" tabindex="-1"></a>        <span class="kw">operator</span><span class="op">==(</span><span class="kw">const</span> mapping<span class="op">&amp;</span>, <span class="kw">const</span> mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb50-48"><a href="#cb50-48" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb50-49"><a href="#cb50-49" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Preconditions:</em> <code>Layout</code> shall meet the
<code>mdspan</code> layout mapping policy requirements.</p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Constraints:</em> <code>Extents::rank()</code> equals 2.</p>
<div class="sourceCode" id="cb51"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb51-1"><a href="#cb51-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span> mapping<span class="op">(</span><span class="kw">const</span> <em>nested-mapping-type</em><span class="op">&amp;</span> map<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Effects:</em> Initializes <em><code>nested-mapping</code></em> with
<code>map</code>.</p>
<div class="sourceCode" id="cb52"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb52-1"><a href="#cb52-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> extents_type extents<span class="op">()</span> <span class="kw">const</span></span>
<span id="cb52-2"><a href="#cb52-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">.</span>extents<span class="op">()))</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>transpose-extents</code></em> <code>(</code>
<em><code>nested_mapping</code></em> <code>.extents());</code>.</p>
<div class="sourceCode" id="cb53"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb53-1"><a href="#cb53-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> size_type required_span_size<span class="op">()</span> <span class="kw">const</span></span>
<span id="cb53-2"><a href="#cb53-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">.</span>required_span_size<span class="op">()))</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-mapping</code></em>
<code>.required_span_size();</code>.</p>
<div class="sourceCode" id="cb54"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb54-1"><a href="#cb54-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Indices<span class="op">&gt;</span></span>
<span id="cb54-2"><a href="#cb54-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> size_type <span class="kw">operator</span><span class="op">()(</span>Indices<span class="op">...</span> indices<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb54-3"><a href="#cb54-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">(</span>indices<span class="op">...)))</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-mapping</code></em>
<code>(last_2_indices_reversed);</code>, where
<code>last_2_indices_reversed</code> is the result of reversing the last
two elements of <code>indices</code>.</p>
<div class="sourceCode" id="cb55"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb55-1"><a href="#cb55-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <em>nested-mapping-type</em> nested_mapping<span class="op">()</span> <span class="kw">const</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">13</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-mapping</code></em> <code>;</code>.</p>
<div class="sourceCode" id="cb56"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb56-1"><a href="#cb56-1" aria-hidden="true" tabindex="-1"></a><span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_unique<span class="op">()</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">14</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-mapping-type</code></em>
<code>::is_always_unique();</code>.</p>
<div class="sourceCode" id="cb57"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb57-1"><a href="#cb57-1" aria-hidden="true" tabindex="-1"></a><span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_contiguous<span class="op">()</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">15</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-mapping-type</code></em>
<code>::is_always_contiguous();</code>.</p>
<div class="sourceCode" id="cb58"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb58-1"><a href="#cb58-1" aria-hidden="true" tabindex="-1"></a><span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_strided<span class="op">()</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">16</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-mapping-type</code></em>
<code>::is_always_strided();</code>.</p>
<div class="sourceCode" id="cb59"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb59-1"><a href="#cb59-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> is_unique<span class="op">()</span> <span class="kw">const</span></span>
<span id="cb59-2"><a href="#cb59-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">.</span>is_unique<span class="op">()))</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">17</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-mapping</code></em> <code>.is_unique();</code>.</p>
<div class="sourceCode" id="cb60"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb60-1"><a href="#cb60-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> is_contiguous<span class="op">()</span> <span class="kw">const</span></span>
<span id="cb60-2"><a href="#cb60-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">.</span>is_contiguous<span class="op">()))</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">18</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-mapping</code></em> <code>.is_contiguous();</code>.</p>
<div class="sourceCode" id="cb61"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb61-1"><a href="#cb61-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> is_strided<span class="op">()</span> <span class="kw">const</span></span>
<span id="cb61-2"><a href="#cb61-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">.</span>is_strided<span class="op">()))</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">19</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-mapping</code></em> <code>.is_strided();</code>.</p>
<div class="sourceCode" id="cb62"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb62-1"><a href="#cb62-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> size_type stride<span class="op">(</span><span class="dt">size_t</span> r<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb62-2"><a href="#cb62-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">noexcept</span><span class="op">(</span><span class="kw">noexcept</span><span class="op">(</span><em>nested-mapping</em><span class="op">.</span>stride<span class="op">(</span>r<span class="op">)))</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">20</a></span>
<em>Constraints:</em> <code>is_always_strided()</code> is
<code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">21</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>nested-mapping</code></em> <code>.stride(s);</code>, where</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(21.1)</a></span>
<code>s</code> is <code>rank()</code> - 2 if <code>r</code> equals
<code>rank()</code> - 1,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(21.2)</a></span>
<code>s</code> is <code>rank()</code> - 1 if <code>r</code> equals
<code>rank()</code> - 2, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(21.3)</a></span>
<code>s</code> is <code>r</code> for 0 ≤ <code>r</code> &lt;
<code>in.rank()-2</code>.</p></li>
</ul>
<div class="sourceCode" id="cb63"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb63-1"><a href="#cb63-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb63-2"><a href="#cb63-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span></span>
<span id="cb63-3"><a href="#cb63-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">operator</span><span class="op">==(</span><span class="kw">const</span> mapping<span class="op">&amp;</span>, <span class="kw">const</span> mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">22</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(22.1)</a></span>
<em><code>nested-mapping-type</code></em> and <code>decltype(m.</code>
<em><code>nested-mapping</code></em> <code>)</code> are equality
comparable, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(22.2)</a></span>
<code>OtherExtents::rank()</code> equals <code>rank()</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">23</a></span>
<em>Effects:</em> Equivalent to <em><code>nested-mapping</code></em>
<code>== m.</code> <em><code>nested-mapping</code></em>
<code>;</code>.</p>
<h3 data-number="16.7.2" id="transposed-linalg.transp.transposed"><span class="header-section-number">16.7.2</span> <code>transposed</code>
[linalg.transp.transposed]<a href="#transposed-linalg.transp.transposed" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The <code>transposed</code> function takes a rank-2 <code>mdspan</code>
representing a matrix, and returns a new read-only <code>mdspan</code>
representing the transpose of the input matrix. The input matrix’s data
are not modified, and the returned <code>mdspan</code> accesses the
input matrix’s data in place.</p>
<div class="sourceCode" id="cb64"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb64-1"><a href="#cb64-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType,</span>
<span id="cb64-2"><a href="#cb64-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Extents,</span>
<span id="cb64-3"><a href="#cb64-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Layout,</span>
<span id="cb64-4"><a href="#cb64-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb64-5"><a href="#cb64-5" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> transposed<span class="op">(</span></span>
<span id="cb64-6"><a href="#cb64-6" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span>ElementType, Extents, Layout, Accessor<span class="op">&gt;</span> a<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Let <code>ReturnExtents</code> name the type
<em><code>transpose-extents-t</code></em><code>&lt;Extents&gt;</code>.
Let <code>R</code> name the type
<code>mdspan&lt;ReturnElementType, ReturnExtents, ReturnLayout, ReturnAccessor&gt;</code>,
where</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>ReturnElementType</code> is:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1.1)</a></span> if
<code>Accessor</code> is
<code>default_accessor&lt;ElementType&gt;</code>, then
<code>add_const_t&lt;ElementType&gt;</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1.2)</a></span>
else, <code>ElementType</code>; <i>[Note:</i> For general accessors, the
<code>const ElementType</code> version of the accessor may not exist;
Even if it does, <code>transposed</code> has no way to deduce it
generically. <i>– end note]</i></p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>ReturnLayout</code> is:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2.1)</a></span> if
<code>Layout</code> is <code>layout_left</code>, then
<code>layout_right</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2.2)</a></span>
else if <code>Layout</code> is <code>layout_right</code>, then
<code>layout_left</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2.3)</a></span>
else if <code>Layout</code> is <code>layout_stride</code>, then
<code>layout_stride</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2.4)</a></span>
else if <code>Layout</code> is
<code>layout_left_padded&lt;padding_stride&gt;</code> for some
<code>padding_stride</code>, then
<code>layout_right_padded&lt;padding_stride&gt;</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2.5)</a></span>
else if <code>Layout</code> is
<code>layout_right_padded&lt;padding_stride&gt;</code> for some
<code>padding_stride</code>, then
<code>layout_left_padded&lt;padding_stride&gt;</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2.6)</a></span>
else if <code>Layout</code> is
<code>layout_blas_packed&lt;Triangle, StorageOrder&gt;</code> for some
<code>Triangle</code> and <code>StorageOrder</code>, then
<code>layout_blas_packed&lt;OppositeTriangle, OppositeStorageOrder&gt;</code>,
where</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2.6.1)</a></span>
<code>OppositeTriangle</code> names the type
<code>conditional_t&lt;is_same_v&lt;Triangle, upper_triangle_t&gt;, lower_triangle_t, upper_triangle_t&gt;</code>,
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2.6.2)</a></span>
<code>OppositeStorageOrder</code> names the type
<code>conditional_t&lt;is_same_v&lt;StorageOrder, column_major_t&gt;, row_major_t, column_major_t&gt;</code>;</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2.7)</a></span>
else if <code>Layout</code> is
<code>layout_transpose&lt;NestedLayout&gt;</code> for some
<code>NestedLayout</code>, then <code>NestedLayout</code> <i>[Note:</i>
this optimizes applying <code>transposed</code> twice to an
<code>mdspan</code> with a custom layout, as long as there are no
intervening layout changes <i>– end note]</i>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2.8)</a></span>
else, <code>layout_transpose&lt;Layout&gt;</code>;</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span> and,
<code>ReturnAccessor</code> is:</p>
<ul>
<li><p>if <code>Accessor</code> is
<code>default_accessor&lt;ElementType&gt;</code>, then
<code>default_accessor&lt;add_const_t&lt;ElementType&gt;&gt;</code>;</p></li>
<li><p>else, <code>Accessor</code>.</p></li>
</ul></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Effects:</em></p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
<code>Layout</code> is <code>layout_left</code>,
<code>layout_right</code>, or
<code>layout_blas_packed&lt;Triangle, StorageOrder&gt;</code> for some
<code>Triangle</code> and <code>StorageOrder</code>, then equivalent
to</li>
</ul>
<div class="sourceCode" id="cb65"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb65-1"><a href="#cb65-1" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> R<span class="op">(</span>a<span class="op">.</span>data<span class="op">()</span>,</span>
<span id="cb65-2"><a href="#cb65-2" aria-hidden="true" tabindex="-1"></a>  ReturnMapping<span class="op">(</span><em>transpose-extents</em><span class="op">(</span>a<span class="op">.</span>mapping<span class="op">().</span>extents<span class="op">()))</span>,</span>
<span id="cb65-3"><a href="#cb65-3" aria-hidden="true" tabindex="-1"></a>  a<span class="op">.</span>accessor<span class="op">())</span>;</span></code></pre></div>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
else, if <code>Layout</code> is
<code>layout_left_padded&lt;padding_stride&gt;</code> for some
<code>padding_stride</code>, then equivalent to</li>
</ul>
<div class="sourceCode" id="cb66"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb66-1"><a href="#cb66-1" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> R<span class="op">(</span>a<span class="op">.</span>data<span class="op">()</span>,</span>
<span id="cb66-2"><a href="#cb66-2" aria-hidden="true" tabindex="-1"></a>  ReturnMapping<span class="op">(</span></span>
<span id="cb66-3"><a href="#cb66-3" aria-hidden="true" tabindex="-1"></a>    <em>transpose-extents</em><span class="op">(</span>a<span class="op">.</span>mapping<span class="op">().</span>extents<span class="op">())</span>,</span>
<span id="cb66-4"><a href="#cb66-4" aria-hidden="true" tabindex="-1"></a>    a<span class="op">.</span>mapping<span class="op">().</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">))</span>,</span>
<span id="cb66-5"><a href="#cb66-5" aria-hidden="true" tabindex="-1"></a>  a<span class="op">.</span>accessor<span class="op">())</span>;</span></code></pre></div>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span>
else, if <code>Layout</code> is
<code>layout_right_padded&lt;padding_stride&gt;</code> for some
<code>padding_stride</code>, then equivalent to</li>
</ul>
<div class="sourceCode" id="cb67"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb67-1"><a href="#cb67-1" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> R<span class="op">(</span>a<span class="op">.</span>data<span class="op">()</span>,</span>
<span id="cb67-2"><a href="#cb67-2" aria-hidden="true" tabindex="-1"></a>  ReturnMapping<span class="op">(</span></span>
<span id="cb67-3"><a href="#cb67-3" aria-hidden="true" tabindex="-1"></a>    <em>transpose-extents</em><span class="op">(</span>a<span class="op">.</span>mapping<span class="op">().</span>extents<span class="op">())</span>,</span>
<span id="cb67-4"><a href="#cb67-4" aria-hidden="true" tabindex="-1"></a>    a<span class="op">.</span>mapping<span class="op">().</span>stride<span class="op">(</span><span class="dv">0</span><span class="op">))</span>,</span>
<span id="cb67-5"><a href="#cb67-5" aria-hidden="true" tabindex="-1"></a>  a<span class="op">.</span>accessor<span class="op">())</span>;</span></code></pre></div>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(3.4)</a></span>
else, if <code>Layout</code> is <code>layout_stride</code>, then
equivalent to <i>[Note:</i> this reverses the strides as well as the
extents <i>– end note]</i></li>
</ul>
<div class="sourceCode" id="cb68"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb68-1"><a href="#cb68-1" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> R<span class="op">(</span>a<span class="op">.</span>data<span class="op">()</span>,</span>
<span id="cb68-2"><a href="#cb68-2" aria-hidden="true" tabindex="-1"></a>  ReturnMapping<span class="op">(</span></span>
<span id="cb68-3"><a href="#cb68-3" aria-hidden="true" tabindex="-1"></a>    <em>transpose-extents</em><span class="op">(</span>a<span class="op">.</span>mapping<span class="op">().</span>extents<span class="op">())</span>,</span>
<span id="cb68-4"><a href="#cb68-4" aria-hidden="true" tabindex="-1"></a>    array<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">()</span>, a<span class="op">.</span>mapping<span class="op">().</span>rank<span class="op">()&gt;{</span></span>
<span id="cb68-5"><a href="#cb68-5" aria-hidden="true" tabindex="-1"></a>      a<span class="op">.</span>mapping<span class="op">().</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">)</span>,</span>
<span id="cb68-6"><a href="#cb68-6" aria-hidden="true" tabindex="-1"></a>      a<span class="op">.</span>mapping<span class="op">().</span>stride<span class="op">(</span><span class="dv">0</span><span class="op">)})</span>,</span>
<span id="cb68-7"><a href="#cb68-7" aria-hidden="true" tabindex="-1"></a>    a<span class="op">.</span>accessor<span class="op">())</span>;</span></code></pre></div>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(3.5)</a></span>
else, if <code>Layout</code> is
<code>layout_transpose&lt;NestedLayout&gt;</code> for some
<code>NestedLayout</code>, then equivalent to <i>[Note:</i> getting the
nested mapping untransposes the extents <i>– end note]</i></li>
</ul>
<div class="sourceCode" id="cb69"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb69-1"><a href="#cb69-1" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> R<span class="op">(</span>a<span class="op">.</span>data<span class="op">()</span>, a<span class="op">.</span>mapping<span class="op">().</span>nested_mapping<span class="op">()</span>, a<span class="op">.</span>accessor<span class="op">())</span>;</span></code></pre></div>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(3.6)</a></span>
else, equivalent to
<code>return R(a.data(), ReturnMapping(a.mapping()), a.accessor());</code>,
where <code>ReturnMapping</code> names the type
<code>typename layout_transpose&lt;Layout&gt;::template mapping&lt;ReturnExtents&gt;</code>.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Remarks:</em> The elements of the returned <code>mdspan</code> are
read only.</p>
<p>[<em>Example:</em></p>
<div class="sourceCode" id="cb70"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb70-1"><a href="#cb70-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> test_transposed<span class="op">(</span>mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">3</span>, <span class="dv">4</span><span class="op">&gt;&gt;</span> a<span class="op">)</span></span>
<span id="cb70-2"><a href="#cb70-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb70-3"><a href="#cb70-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="kw">auto</span> num_rows <span class="op">=</span> a<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>;</span>
<span id="cb70-4"><a href="#cb70-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="kw">auto</span> num_cols <span class="op">=</span> a<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb70-5"><a href="#cb70-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-6"><a href="#cb70-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> a_t <span class="op">=</span> transposed<span class="op">(</span>a<span class="op">)</span>;</span>
<span id="cb70-7"><a href="#cb70-7" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>num_rows <span class="op">==</span> a_t<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb70-8"><a href="#cb70-8" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>num_cols <span class="op">==</span> a_t<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb70-9"><a href="#cb70-9" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>a<span class="op">.</span>stride<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> a_t<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb70-10"><a href="#cb70-10" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>a<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">==</span> a_t<span class="op">.</span>stride<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb70-11"><a href="#cb70-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-12"><a href="#cb70-12" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> row <span class="op">=</span> <span class="dv">0</span>; row <span class="op">&lt;</span> num_rows; <span class="op">++</span>row<span class="op">)</span> <span class="op">{</span></span>
<span id="cb70-13"><a href="#cb70-13" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> col <span class="op">=</span> <span class="dv">0</span>; col <span class="op">&lt;</span> num_rows; <span class="op">++</span>col<span class="op">)</span> <span class="op">{</span></span>
<span id="cb70-14"><a href="#cb70-14" aria-hidden="true" tabindex="-1"></a>      <span class="ot">assert</span><span class="op">(</span>a<span class="op">[</span>row, col<span class="op">]</span> <span class="op">==</span> a_t<span class="op">[</span>col, row<span class="op">])</span>;</span>
<span id="cb70-15"><a href="#cb70-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb70-16"><a href="#cb70-16" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb70-17"><a href="#cb70-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-18"><a href="#cb70-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> a_t_t <span class="op">=</span> transposed<span class="op">(</span>a_t<span class="op">)</span>;</span>
<span id="cb70-19"><a href="#cb70-19" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>num_rows <span class="op">==</span> a_t_t<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb70-20"><a href="#cb70-20" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>num_cols <span class="op">==</span> a_t_t<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb70-21"><a href="#cb70-21" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>a<span class="op">.</span>stride<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> a_t_t<span class="op">.</span>stride<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb70-22"><a href="#cb70-22" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>a<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">==</span> a_t_t<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb70-23"><a href="#cb70-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-24"><a href="#cb70-24" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> row <span class="op">=</span> <span class="dv">0</span>; row <span class="op">&lt;</span> num_rows; <span class="op">++</span>row<span class="op">)</span> <span class="op">{</span></span>
<span id="cb70-25"><a href="#cb70-25" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> col <span class="op">=</span> <span class="dv">0</span>; col <span class="op">&lt;</span> num_rows; <span class="op">++</span>col<span class="op">)</span> <span class="op">{</span></span>
<span id="cb70-26"><a href="#cb70-26" aria-hidden="true" tabindex="-1"></a>      <span class="ot">assert</span><span class="op">(</span>a<span class="op">[</span>row, col<span class="op">]</span> <span class="op">==</span> a_t_t<span class="op">[</span>row, col<span class="op">])</span>;</span>
<span id="cb70-27"><a href="#cb70-27" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb70-28"><a href="#cb70-28" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb70-29"><a href="#cb70-29" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>–<em>end example</em>]</p>
<h2 data-number="16.8" id="conjugate-transpose-transform-linalg.conj_transp"><span class="header-section-number">16.8</span> Conjugate transpose transform
[linalg.conj_transp]<a href="#conjugate-transpose-transform-linalg.conj_transp" class="self-link"></a></h2>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The <code>conjugate_transposed</code> function returns a conjugate
transpose view of an object. This combines the effects of
<code>transposed</code> and <code>conjugated</code>.</p>
<div class="sourceCode" id="cb71"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb71-1"><a href="#cb71-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType,</span>
<span id="cb71-2"><a href="#cb71-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Extents,</span>
<span id="cb71-3"><a href="#cb71-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Layout,</span>
<span id="cb71-4"><a href="#cb71-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb71-5"><a href="#cb71-5" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> conjugate_transposed<span class="op">(</span></span>
<span id="cb71-6"><a href="#cb71-6" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span>ElementType, Extents, Layout, Accessor<span class="op">&gt;</span> a<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> Equivalent to
<code>return conjugated(transposed(a));</code>.</p>
<p>[<em>Example:</em></p>
<div class="sourceCode" id="cb72"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb72-1"><a href="#cb72-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> test_conjugate_transposed<span class="op">(</span></span>
<span id="cb72-2"><a href="#cb72-2" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span>complex<span class="op">&lt;</span><span class="dt">double</span><span class="op">&gt;</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">3</span>, <span class="dv">4</span><span class="op">&gt;&gt;</span> a<span class="op">)</span></span>
<span id="cb72-3"><a href="#cb72-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb72-4"><a href="#cb72-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="kw">auto</span> num_rows <span class="op">=</span> a<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>;</span>
<span id="cb72-5"><a href="#cb72-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="kw">auto</span> num_cols <span class="op">=</span> a<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb72-6"><a href="#cb72-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb72-7"><a href="#cb72-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> a_ct <span class="op">=</span> conjugate_transposed<span class="op">(</span>a<span class="op">)</span>;</span>
<span id="cb72-8"><a href="#cb72-8" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>num_rows <span class="op">==</span> a_ct<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb72-9"><a href="#cb72-9" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>num_cols <span class="op">==</span> a_ct<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb72-10"><a href="#cb72-10" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>a<span class="op">.</span>stride<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> a_ct<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb72-11"><a href="#cb72-11" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>a<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">==</span> a_ct<span class="op">.</span>stride<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb72-12"><a href="#cb72-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb72-13"><a href="#cb72-13" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> row <span class="op">=</span> <span class="dv">0</span>; row <span class="op">&lt;</span> num_rows; <span class="op">++</span>row<span class="op">)</span> <span class="op">{</span></span>
<span id="cb72-14"><a href="#cb72-14" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> col <span class="op">=</span> <span class="dv">0</span>; col <span class="op">&lt;</span> num_rows; <span class="op">++</span>col<span class="op">)</span> <span class="op">{</span></span>
<span id="cb72-15"><a href="#cb72-15" aria-hidden="true" tabindex="-1"></a>      <span class="ot">assert</span><span class="op">(</span>a<span class="op">[</span>row, col<span class="op">]</span> <span class="op">==</span> conj<span class="op">(</span>a_ct<span class="op">[</span>col, row<span class="op">]))</span>;</span>
<span id="cb72-16"><a href="#cb72-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb72-17"><a href="#cb72-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb72-18"><a href="#cb72-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb72-19"><a href="#cb72-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> a_ct_ct <span class="op">=</span> conjugate_transposed<span class="op">(</span>a_ct<span class="op">)</span>;</span>
<span id="cb72-20"><a href="#cb72-20" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>num_rows <span class="op">==</span> a_ct_ct<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb72-21"><a href="#cb72-21" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>num_cols <span class="op">==</span> a_ct_ct<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb72-22"><a href="#cb72-22" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>a<span class="op">.</span>stride<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> a_ct_ct<span class="op">.</span>stride<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb72-23"><a href="#cb72-23" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>a<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">==</span> a_ct_ct<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb72-24"><a href="#cb72-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb72-25"><a href="#cb72-25" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> row <span class="op">=</span> <span class="dv">0</span>; row <span class="op">&lt;</span> num_rows; <span class="op">++</span>row<span class="op">)</span> <span class="op">{</span></span>
<span id="cb72-26"><a href="#cb72-26" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> col <span class="op">=</span> <span class="dv">0</span>; col <span class="op">&lt;</span> num_rows; <span class="op">++</span>col<span class="op">)</span> <span class="op">{</span></span>
<span id="cb72-27"><a href="#cb72-27" aria-hidden="true" tabindex="-1"></a>      <span class="ot">assert</span><span class="op">(</span>a<span class="op">[</span>row, col<span class="op">]</span> <span class="op">==</span> a_ct_ct<span class="op">[</span>row, col<span class="op">])</span>;</span>
<span id="cb72-28"><a href="#cb72-28" aria-hidden="true" tabindex="-1"></a>      <span class="ot">assert</span><span class="op">(</span>conj<span class="op">(</span>a_ct<span class="op">[</span>col, row<span class="op">])</span> <span class="op">==</span> a_ct_ct<span class="op">[</span>row, col<span class="op">])</span>;</span>
<span id="cb72-29"><a href="#cb72-29" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb72-30"><a href="#cb72-30" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb72-31"><a href="#cb72-31" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>–<em>end example</em>]</p>
<h2 data-number="16.9" id="exposition-only-concepts-and-traits-linalg.concepts"><span class="header-section-number">16.9</span> Exposition-only concepts and
traits [linalg.concepts]<a href="#exposition-only-concepts-and-traits-linalg.concepts" class="self-link"></a></h2>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The exposition-only concepts defined in this section constrain the
algorithms in <em>[linalg.algs]</em>. The exposition-only trait(s)
defined in this section help define the exposition-only concepts.</p>
<div class="sourceCode" id="cb73"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb73-1"><a href="#cb73-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb73-2"><a href="#cb73-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>is-mdspan</em> <span class="op">:</span> false_type <span class="op">{}</span>; <span class="co">// exposition only</span></span>
<span id="cb73-3"><a href="#cb73-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb73-4"><a href="#cb73-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="kw">class</span> Extents, <span class="kw">class</span> Layout, <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb73-5"><a href="#cb73-5" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>is-mdspan</em><span class="op">&lt;</span>mdspan<span class="op">&lt;</span>ElementType, Extents, Layout, Accessor<span class="op">&gt;&gt;</span> <span class="op">:</span> true_type <span class="op">{}</span>; <span class="co">// exposition only</span></span>
<span id="cb73-6"><a href="#cb73-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb73-7"><a href="#cb73-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb73-8"><a href="#cb73-8" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>in-vector</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb73-9"><a href="#cb73-9" aria-hidden="true" tabindex="-1"></a>  <em>is-mdspan</em><span class="op">&lt;</span>T<span class="op">&gt;::</span>value <span class="op">&amp;&amp;</span></span>
<span id="cb73-10"><a href="#cb73-10" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">1</span>;</span>
<span id="cb73-11"><a href="#cb73-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb73-12"><a href="#cb73-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb73-13"><a href="#cb73-13" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>out-vector</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb73-14"><a href="#cb73-14" aria-hidden="true" tabindex="-1"></a>  <em>is-mdspan</em><span class="op">&lt;</span>T<span class="op">&gt;::</span>value <span class="op">&amp;&amp;</span></span>
<span id="cb73-15"><a href="#cb73-15" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">1</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-16"><a href="#cb73-16" aria-hidden="true" tabindex="-1"></a>  is_same_v<span class="op">&lt;</span>remove_const_t<span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span>, <span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-17"><a href="#cb73-17" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>is_always_unique<span class="op">()</span>;</span>
<span id="cb73-18"><a href="#cb73-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb73-19"><a href="#cb73-19" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb73-20"><a href="#cb73-20" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>inout-vector</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb73-21"><a href="#cb73-21" aria-hidden="true" tabindex="-1"></a>  <em>is-mdspan</em><span class="op">&lt;</span>T<span class="op">&gt;::</span>value <span class="op">&amp;&amp;</span></span>
<span id="cb73-22"><a href="#cb73-22" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">1</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-23"><a href="#cb73-23" aria-hidden="true" tabindex="-1"></a>  is_same_v<span class="op">&lt;</span>remove_const_t<span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span>, <span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-24"><a href="#cb73-24" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>is_always_unique<span class="op">()</span>;</span>
<span id="cb73-25"><a href="#cb73-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb73-26"><a href="#cb73-26" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb73-27"><a href="#cb73-27" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>in-matrix</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb73-28"><a href="#cb73-28" aria-hidden="true" tabindex="-1"></a>  <em>is-mdspan</em><span class="op">&lt;</span>T<span class="op">&gt;::</span>value <span class="op">&amp;&amp;</span></span>
<span id="cb73-29"><a href="#cb73-29" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">2</span>;</span>
<span id="cb73-30"><a href="#cb73-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb73-31"><a href="#cb73-31" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb73-32"><a href="#cb73-32" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>out-matrix</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb73-33"><a href="#cb73-33" aria-hidden="true" tabindex="-1"></a>  <em>is-mdspan</em><span class="op">&lt;</span>T<span class="op">&gt;::</span>value <span class="op">&amp;&amp;</span></span>
<span id="cb73-34"><a href="#cb73-34" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">2</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-35"><a href="#cb73-35" aria-hidden="true" tabindex="-1"></a>  is_same_v<span class="op">&lt;</span>remove_const_t<span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span>, <span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-36"><a href="#cb73-36" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>is_always_unique<span class="op">()</span>;</span>
<span id="cb73-37"><a href="#cb73-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb73-38"><a href="#cb73-38" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb73-39"><a href="#cb73-39" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>inout-matrix</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb73-40"><a href="#cb73-40" aria-hidden="true" tabindex="-1"></a>  <em>is-mdspan</em><span class="op">&lt;</span>T<span class="op">&gt;::</span>value <span class="op">&amp;&amp;</span></span>
<span id="cb73-41"><a href="#cb73-41" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">2</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-42"><a href="#cb73-42" aria-hidden="true" tabindex="-1"></a>  is_same_v<span class="op">&lt;</span>remove_const_t<span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span>, <span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-43"><a href="#cb73-43" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>is_always_unique<span class="op">()</span>;</span>
<span id="cb73-44"><a href="#cb73-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb73-45"><a href="#cb73-45" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb73-46"><a href="#cb73-46" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>possibly-packed-inout-matrix</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb73-47"><a href="#cb73-47" aria-hidden="true" tabindex="-1"></a>  <em>is-mdspan</em><span class="op">&lt;</span>T<span class="op">&gt;::</span>value <span class="op">&amp;&amp;</span></span>
<span id="cb73-48"><a href="#cb73-48" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">2</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-49"><a href="#cb73-49" aria-hidden="true" tabindex="-1"></a>  is_same_v<span class="op">&lt;</span>remove_const_t<span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span>, <span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-50"><a href="#cb73-50" aria-hidden="true" tabindex="-1"></a>  <span class="op">(</span>T<span class="op">::</span>is_always_unique<span class="op">()</span> <span class="op">||</span> is_same_v<span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">::</span>layout_type, layout_blas_packed<span class="op">&gt;)</span>;</span>
<span id="cb73-51"><a href="#cb73-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb73-52"><a href="#cb73-52" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb73-53"><a href="#cb73-53" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>in-object</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb73-54"><a href="#cb73-54" aria-hidden="true" tabindex="-1"></a>  <em>is-mdspan</em><span class="op">&lt;</span>T<span class="op">&gt;::</span>value <span class="op">&amp;&amp;</span></span>
<span id="cb73-55"><a href="#cb73-55" aria-hidden="true" tabindex="-1"></a>  <span class="op">(</span>T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">1</span> <span class="op">||</span> T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb73-56"><a href="#cb73-56" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb73-57"><a href="#cb73-57" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb73-58"><a href="#cb73-58" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>out-object</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb73-59"><a href="#cb73-59" aria-hidden="true" tabindex="-1"></a>  <em>is-mdspan</em><span class="op">&lt;</span>T<span class="op">&gt;::</span>value <span class="op">&amp;&amp;</span></span>
<span id="cb73-60"><a href="#cb73-60" aria-hidden="true" tabindex="-1"></a>  <span class="op">(</span>T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">1</span> <span class="op">||</span> T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">2</span><span class="op">)</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-61"><a href="#cb73-61" aria-hidden="true" tabindex="-1"></a>  is_same_v<span class="op">&lt;</span>remove_const_t<span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span>, <span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-62"><a href="#cb73-62" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>is_always_unique<span class="op">()</span>;</span>
<span id="cb73-63"><a href="#cb73-63" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb73-64"><a href="#cb73-64" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb73-65"><a href="#cb73-65" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>inout-object</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb73-66"><a href="#cb73-66" aria-hidden="true" tabindex="-1"></a>  <em>is-mdspan</em><span class="op">&lt;</span>T<span class="op">&gt;::</span>value <span class="op">&amp;&amp;</span></span>
<span id="cb73-67"><a href="#cb73-67" aria-hidden="true" tabindex="-1"></a>  <span class="op">(</span>T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">1</span> <span class="op">||</span> T<span class="op">::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">2</span><span class="op">)</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-68"><a href="#cb73-68" aria-hidden="true" tabindex="-1"></a>  is_same_v<span class="op">&lt;</span>remove_const_t<span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span>, <span class="kw">typename</span> T<span class="op">::</span>element_type<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb73-69"><a href="#cb73-69" aria-hidden="true" tabindex="-1"></a>  T<span class="op">::</span>is_always_unique<span class="op">()</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
If an algorithm in <em>[linalg.algs]</em> accesses the elements of an
<em><code>in-vector</code></em>, <em><code>in-matrix</code></em>, or
<em><code>in-object</code></em>, it will do so in read-only fashion.</p>
<p><i>[Note:</i> The <code>element_type</code> of an
<em><code>in-vector</code></em>, <em><code>in-matrix</code></em>, or
<em><code>in-object</code></em> need not be <code>const</code>, because
an mdspan accessor with a nonconst <code>element_type</code> need not
necessarily be convertible to an accessor with a const
<code>element_type</code>. <i>– end note]</i></p>
<p><i>[Note:</i> The exposition-only concept
<em><code>possibly-packed-inout-matrix</code></em> constrains symmetric
and Hermitian update algorithms. These may write either to a
unique-layout mdspan or to a <code>layout_blas_packed</code> mdspan
(whose layout is nonunique). <i>– end note]</i></p>
<h2 data-number="16.10" id="algorithms-linalg.algs"><span class="header-section-number">16.10</span> Algorithms [linalg.algs]<a href="#algorithms-linalg.algs" class="self-link"></a></h2>
<h3 data-number="16.10.1" id="requirements-based-on-template-parameter-name-linalg.algs.reqs"><span class="header-section-number">16.10.1</span> Requirements based on
template parameter name [linalg.algs.reqs]<a href="#requirements-based-on-template-parameter-name-linalg.algs.reqs" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Throughout this Clause, where the template parameters are not
constrained, the names of template parameters are used to express type
requirements. In the requirements below, we use <code>*</code> in a
typename to denote a “wildcard,” that matches zero characters,
<code>_1</code>, <code>_2</code>, <code>_3</code>, or other things as
appropriate.</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
Algorithms that have a template parameter named
<code>ExecutionPolicy</code> are parallel algorithms
<strong>[algorithms.parallel.defns]</strong>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>Real</code> is any type such that <code>complex&lt;Real&gt;</code>
is specified. <i>[Note:</i> See
<strong>[complex.numbers.general]</strong>. <i>– end note]</i></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
<code>Triangle</code> is either <code>upper_triangle_t</code> or
<code>lower_triangle_t</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span>
<code>DiagonalStorage</code> is either
<code>implicit_unit_diagonal_t</code> or
<code>explicit_diagonal_t</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.5)</a></span>
<code>BinaryDivideOp</code> template parameters are a binary function
object (<strong>[function.objects]</strong>).</p></li>
</ul>
<h3 data-number="16.10.2" id="blas-1-functions-linalg.algs.blas1"><span class="header-section-number">16.10.2</span> BLAS 1 functions
[linalg.algs.blas1]<a href="#blas-1-functions-linalg.algs.blas1" class="self-link"></a></h3>
<p><i>[Note:</i> The BLAS developed in three “levels”: 1, 2, and 3. BLAS
1 includes vector-vector operations, BLAS 2 matrix-vector operations,
and BLAS 3 matrix-matrix operations. The level coincides with the number
of nested loops in a naïve sequential implementation of the operation.
Increasing level also comes with increasing potential for data reuse.
The BLAS traditionally lists computing a Givens rotation among the BLAS
1 operations, even though it only operates on scalars. <i>– end
note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Complexity:</em> All algorithms in this Clause with
<code>mdspan</code> parameters perform a count of <code>mdspan</code>
array accesses and arithmetic operations that is linear in the maximum
product of extents of any <code>mdspan</code> parameter.</p>
<h4 data-number="16.10.2.1" id="givens-rotations-linalg.algs.blas1.givens"><span class="header-section-number">16.10.2.1</span> Givens rotations
[linalg.algs.blas1.givens]<a href="#givens-rotations-linalg.algs.blas1.givens" class="self-link"></a></h4>
<h5 data-number="16.10.2.1.1" id="compute-givens-rotation-linalg.algs.blas1.givens.lartg"><span class="header-section-number">16.10.2.1.1</span> Compute Givens rotation
[linalg.algs.blas1.givens.lartg]<a href="#compute-givens-rotation-linalg.algs.blas1.givens.lartg" class="self-link"></a></h5>
<div class="sourceCode" id="cb74"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb74-1"><a href="#cb74-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb74-2"><a href="#cb74-2" aria-hidden="true" tabindex="-1"></a>givens_rotation_setup_result<span class="op">&lt;</span>Real<span class="op">&gt;</span></span>
<span id="cb74-3"><a href="#cb74-3" aria-hidden="true" tabindex="-1"></a>givens_rotation_setup<span class="op">(</span><span class="kw">const</span> Real a,</span>
<span id="cb74-4"><a href="#cb74-4" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">const</span> Real b<span class="op">)</span>;</span>
<span id="cb74-5"><a href="#cb74-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb74-6"><a href="#cb74-6" aria-hidden="true" tabindex="-1"></a>givens_rotation_setup_result<span class="op">&lt;</span>complex<span class="op">&lt;</span>Real<span class="op">&gt;&gt;</span></span>
<span id="cb74-7"><a href="#cb74-7" aria-hidden="true" tabindex="-1"></a>givens_rotation_setup<span class="op">(</span><span class="kw">const</span> complex<span class="op">&lt;</span>Real<span class="op">&gt;&amp;</span> a,</span>
<span id="cb74-8"><a href="#cb74-8" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">const</span> complex<span class="op">&lt;</span>Real<span class="op">&gt;&amp;</span> b<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
This function computes the plane (Givens) rotation represented by the
two values <code>c</code> and <code>s</code> such that the 2x2 system of
equations <i>[Note:</i> use of monospaced text in this equation does not
indicate C++ code <i>– end note]</i></p>
<div class="sourceCode" id="cb75"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb75-1"><a href="#cb75-1" aria-hidden="true" tabindex="-1"></a>[c        s]   [a]   [r]</span>
<span id="cb75-2"><a href="#cb75-2" aria-hidden="true" tabindex="-1"></a>[          ] * [ ] = [ ]</span>
<span id="cb75-3"><a href="#cb75-3" aria-hidden="true" tabindex="-1"></a>[-conj(s) c]   [b]   [0]</span></code></pre></div>
<p>holds, where <code>c</code> is always a real scalar, and
<code>c*c + abs(s)*abs(s)</code> equals one. That is, <code>c</code> and
<code>s</code> represent a 2 x 2 matrix, that when multiplied by the
right by the input vector whose components are <code>a</code> and
<code>b</code>, produces a result vector whose first component
<code>r</code> is the Euclidean norm of the input vector, and whose
second component as zero.</p>
<p><i>[Note:</i> This function corresponds to the LAPACK function
<code>xLARTG</code>. The BLAS variant <code>xROTG</code> takes four
arguments – <code>a</code>, <code>b</code>, <code>c</code>, and
<code>s</code>– and overwrites the input <code>a</code> with
<code>r</code>. We have chosen <code>xLARTG</code>’s interface because
it separates input and output, and to encourage following
<code>xLARTG</code>’s more careful implementation. <i>– end
note]</i></p>
<p><i>[Note:</i> <code>givens_rotation_setup</code> has an overload for
complex numbers, because the output argument <code>c</code> (cosine) is
a signed magnitude. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Returns:</em> <code>{c, s, r}</code>, where <code>c</code> and
<code>s</code> form the plane (Givens) rotation corresponding to the
input <code>a</code> and <code>b</code>, and <code>r</code> is the
Euclidean norm of the two-component vector formed by <code>a</code> and
<code>b</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Throws:</em> Nothing.</p>
<h5 data-number="16.10.2.1.2" id="apply-a-computed-givens-rotation-to-vectors-linalg.algs.blas1.givens.rot"><span class="header-section-number">16.10.2.1.2</span> Apply a computed Givens
rotation to vectors [linalg.algs.blas1.givens.rot]<a href="#apply-a-computed-givens-rotation-to-vectors-linalg.algs.blas1.givens.rot" class="self-link"></a></h5>
<div class="sourceCode" id="cb76"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb76-1"><a href="#cb76-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>inout-vector</em> InOutVec1,</span>
<span id="cb76-2"><a href="#cb76-2" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec2,</span>
<span id="cb76-3"><a href="#cb76-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb76-4"><a href="#cb76-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> givens_rotation_apply<span class="op">(</span></span>
<span id="cb76-5"><a href="#cb76-5" aria-hidden="true" tabindex="-1"></a>  InOutVec1 x,</span>
<span id="cb76-6"><a href="#cb76-6" aria-hidden="true" tabindex="-1"></a>  InOutVec2 y,</span>
<span id="cb76-7"><a href="#cb76-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Real c,</span>
<span id="cb76-8"><a href="#cb76-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Real s<span class="op">)</span>;</span>
<span id="cb76-9"><a href="#cb76-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb76-10"><a href="#cb76-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb76-11"><a href="#cb76-11" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec1,</span>
<span id="cb76-12"><a href="#cb76-12" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec2,</span>
<span id="cb76-13"><a href="#cb76-13" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb76-14"><a href="#cb76-14" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> givens_rotation_apply<span class="op">(</span></span>
<span id="cb76-15"><a href="#cb76-15" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb76-16"><a href="#cb76-16" aria-hidden="true" tabindex="-1"></a>  InOutVec1 x,</span>
<span id="cb76-17"><a href="#cb76-17" aria-hidden="true" tabindex="-1"></a>  InOutVec2 y,</span>
<span id="cb76-18"><a href="#cb76-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Real c,</span>
<span id="cb76-19"><a href="#cb76-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Real s<span class="op">)</span>;</span>
<span id="cb76-20"><a href="#cb76-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb76-21"><a href="#cb76-21" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>inout-vector</em> InOutVec1,</span>
<span id="cb76-22"><a href="#cb76-22" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec2,</span>
<span id="cb76-23"><a href="#cb76-23" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb76-24"><a href="#cb76-24" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> givens_rotation_apply<span class="op">(</span></span>
<span id="cb76-25"><a href="#cb76-25" aria-hidden="true" tabindex="-1"></a>  InOutVec1 x,</span>
<span id="cb76-26"><a href="#cb76-26" aria-hidden="true" tabindex="-1"></a>  InOutVec2 y,</span>
<span id="cb76-27"><a href="#cb76-27" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Real c,</span>
<span id="cb76-28"><a href="#cb76-28" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> complex<span class="op">&lt;</span>Real<span class="op">&gt;</span> s<span class="op">)</span>;</span>
<span id="cb76-29"><a href="#cb76-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb76-30"><a href="#cb76-30" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb76-31"><a href="#cb76-31" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec1,</span>
<span id="cb76-32"><a href="#cb76-32" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec2,</span>
<span id="cb76-33"><a href="#cb76-33" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Real<span class="op">&gt;</span></span>
<span id="cb76-34"><a href="#cb76-34" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> givens_rotation_apply<span class="op">(</span></span>
<span id="cb76-35"><a href="#cb76-35" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb76-36"><a href="#cb76-36" aria-hidden="true" tabindex="-1"></a>  InOutVec1 x,</span>
<span id="cb76-37"><a href="#cb76-37" aria-hidden="true" tabindex="-1"></a>  InOutVec2 y,</span>
<span id="cb76-38"><a href="#cb76-38" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> Real c,</span>
<span id="cb76-39"><a href="#cb76-39" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> complex<span class="op">&lt;</span>Real<span class="op">&gt;</span> s<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xROT</code>. <code>c</code> and <code>s</code> form a plane
(Givens) rotation. Users normally would compute <code>c</code> and
<code>s</code> using <code>givens_rotation_setup</code>, but they are
not required to do this.</p>
<p>For <code>i</code> in the domains of both <code>x</code> and
<code>y</code>, if <span class="math inline"><em>x</em><sub><em>i</em></sub></span> is the value
of <code>x[i]</code> on input and <span class="math inline"><em>y</em><sub><em>i</em></sub></span> is the value
of <code>y[i]</code> on input, then this algorithm computes <span class="math inline"><em>x</em><sub><em>i</em></sub>′</span> such that
<span class="math inline"><em>x</em><sub><em>i</em></sub>′ = <em>c</em><em>x</em><sub><em>i</em></sub> + <em>s</em><em>y</em><sub><em>i</em></sub></span>
and <span class="math inline"><em>y</em><sub><em>i</em></sub>′</span>
such that <span class="math inline"><em>y</em><sub><em>i</em></sub>′ = <em>c</em><em>y</em><sub><em>i</em></sub> − <em>s̄</em><em>x</em><sub><em>i</em></sub></span>
(where <span class="math inline"><em>s̄</em></span> denotes the complex
conjugate of <span class="math inline"><em>s</em></span>), and assigns
<span class="math inline"><em>x</em><sub><em>i</em></sub>′</span> to
<code>x[i]</code> and <span class="math inline"><em>y</em><sub><em>i</em></sub>′</span> to
<code>y[i]</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em> <code>x.extent(0)</code> equals
<code>y.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Mandates:</em> If neither <code>x.static_extent(0)</code> nor
<code>y.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>x.static_extent(0)</code> equals
<code>y.static_extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Effects:</em> Applies the plane (Givens) rotation specified by
<code>c</code> and <code>s</code> to the input vectors <code>x</code>
and <code>y</code>, as if the rotation were a 2 x 2 matrix and the input
vectors were successive rows of a matrix with two rows.</p>
<h4 data-number="16.10.2.2" id="swap-matrix-or-vector-elements-linalg.algs.blas1.swap"><span class="header-section-number">16.10.2.2</span> Swap matrix or vector
elements [linalg.algs.blas1.swap]<a href="#swap-matrix-or-vector-elements-linalg.algs.blas1.swap" class="self-link"></a></h4>
<div class="sourceCode" id="cb77"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb77-1"><a href="#cb77-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>inout-object</em> InOutObj1,</span>
<span id="cb77-2"><a href="#cb77-2" aria-hidden="true" tabindex="-1"></a>         <em>inout-object</em> InOutObj2<span class="op">&gt;</span></span>
<span id="cb77-3"><a href="#cb77-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> swap_elements<span class="op">(</span>InOutObj1 x,</span>
<span id="cb77-4"><a href="#cb77-4" aria-hidden="true" tabindex="-1"></a>                   InOutObj2 y<span class="op">)</span>;</span>
<span id="cb77-5"><a href="#cb77-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb77-6"><a href="#cb77-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb77-7"><a href="#cb77-7" aria-hidden="true" tabindex="-1"></a>         <em>inout-object</em> InOutObj1,</span>
<span id="cb77-8"><a href="#cb77-8" aria-hidden="true" tabindex="-1"></a>         <em>inout-object</em> InOutObj2<span class="op">&gt;</span></span>
<span id="cb77-9"><a href="#cb77-9" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> swap_elements<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb77-10"><a href="#cb77-10" aria-hidden="true" tabindex="-1"></a>                   InOutObj1 x,</span>
<span id="cb77-11"><a href="#cb77-11" aria-hidden="true" tabindex="-1"></a>                   InOutObj2 y<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xSWAP</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em> For all <code>r</code> in 0, 1, …,
<code>x.rank()</code> - 1, <code>x.extent(r)</code> equals
<code>y.extent(r)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> <code>x.rank()</code> equals
<code>y.rank()</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em> For all <code>r</code> in 0, 1, …,
<code>x.rank()</code> - 1, if neither <code>x.static_extent(r)</code>
nor <code>y.static_extent(r)</code> equals <code>dynamic_extent</code>,
then <code>x.static_extent(r)</code> equals
<code>y.static_extent(r)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em> Swap all corresponding elements of <code>x</code> and
<code>y</code>.</p>
<h4 data-number="16.10.2.3" id="multiply-the-elements-of-an-object-in-place-by-a-scalar-linalg.algs.blas1.scal"><span class="header-section-number">16.10.2.3</span> Multiply the elements of
an object in place by a scalar [linalg.algs.blas1.scal]<a href="#multiply-the-elements-of-an-object-in-place-by-a-scalar-linalg.algs.blas1.scal" class="self-link"></a></h4>
<div class="sourceCode" id="cb78"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb78-1"><a href="#cb78-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Scalar,</span>
<span id="cb78-2"><a href="#cb78-2" aria-hidden="true" tabindex="-1"></a>         <em>inout-object</em> InOutObj<span class="op">&gt;</span></span>
<span id="cb78-3"><a href="#cb78-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> scale<span class="op">(</span><span class="kw">const</span> Scalar alpha,</span>
<span id="cb78-4"><a href="#cb78-4" aria-hidden="true" tabindex="-1"></a>           InOutObj x<span class="op">)</span>;</span>
<span id="cb78-5"><a href="#cb78-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb78-6"><a href="#cb78-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb78-7"><a href="#cb78-7" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Scalar,</span>
<span id="cb78-8"><a href="#cb78-8" aria-hidden="true" tabindex="-1"></a>         <em>inout-object</em> InOutObj<span class="op">&gt;</span></span>
<span id="cb78-9"><a href="#cb78-9" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> scale<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb78-10"><a href="#cb78-10" aria-hidden="true" tabindex="-1"></a>           <span class="kw">const</span> Scalar alpha,</span>
<span id="cb78-11"><a href="#cb78-11" aria-hidden="true" tabindex="-1"></a>           InOutObj x<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xSCAL</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Effects</em>: Overwrites <span class="math inline"><em>x</em></span>
with the result of computing the elementwise multiplication <span class="math inline"><em>α</em><em>x</em></span>, where the scalar <span class="math inline"><em>α</em></span> is <code>alpha</code>.</p>
<h4 data-number="16.10.2.4" id="copy-elements-of-one-matrix-or-vector-into-another-linalg.algs.blas1.copy"><span class="header-section-number">16.10.2.4</span> Copy elements of one
matrix or vector into another [linalg.algs.blas1.copy]<a href="#copy-elements-of-one-matrix-or-vector-into-another-linalg.algs.blas1.copy" class="self-link"></a></h4>
<div class="sourceCode" id="cb79"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb79-1"><a href="#cb79-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-object</em> InObj,</span>
<span id="cb79-2"><a href="#cb79-2" aria-hidden="true" tabindex="-1"></a>         <em>out-object</em> OutObj<span class="op">&gt;</span></span>
<span id="cb79-3"><a href="#cb79-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> copy<span class="op">(</span>InObj x,</span>
<span id="cb79-4"><a href="#cb79-4" aria-hidden="true" tabindex="-1"></a>          OutObj y<span class="op">)</span>;</span>
<span id="cb79-5"><a href="#cb79-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb79-6"><a href="#cb79-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb79-7"><a href="#cb79-7" aria-hidden="true" tabindex="-1"></a>         <em>in-object</em> InObj,</span>
<span id="cb79-8"><a href="#cb79-8" aria-hidden="true" tabindex="-1"></a>         <em>out-object</em> OutObj<span class="op">&gt;</span></span>
<span id="cb79-9"><a href="#cb79-9" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> copy<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb79-10"><a href="#cb79-10" aria-hidden="true" tabindex="-1"></a>          InObj x,</span>
<span id="cb79-11"><a href="#cb79-11" aria-hidden="true" tabindex="-1"></a>          OutObj y<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xCOPY</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em> For all <code>r</code> in 0, 1, …,
<code>x.rank()</code> - 1, <code>x.extent(r)</code> equals
<code>y.extent(r)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> <code>x.rank()</code> equals
<code>y.rank()</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em> For all <code>r</code> in 0, 1, …,
<code>x.rank()</code> - 1, if neither <code>x.static_extent(r)</code>
nor <code>y.static_extent(r)</code> equals <code>dynamic_extent</code>,
then <code>x.static_extent(r)</code> equals
<code>y.static_extent(r)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em> Overwrites the elements of <span class="math inline"><em>y</em></span> with the corresponding elements of
<span class="math inline"><em>x</em></span>.</p>
<h4 data-number="16.10.2.5" id="add-vectors-or-matrices-elementwise-linalg.algs.blas1.add"><span class="header-section-number">16.10.2.5</span> Add vectors or matrices
elementwise [linalg.algs.blas1.add]<a href="#add-vectors-or-matrices-elementwise-linalg.algs.blas1.add" class="self-link"></a></h4>
<div class="sourceCode" id="cb80"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb80-1"><a href="#cb80-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-object</em> InObj1,</span>
<span id="cb80-2"><a href="#cb80-2" aria-hidden="true" tabindex="-1"></a>         <em>in-object</em> InObj2,</span>
<span id="cb80-3"><a href="#cb80-3" aria-hidden="true" tabindex="-1"></a>         <em>out-object</em> OutObj<span class="op">&gt;</span></span>
<span id="cb80-4"><a href="#cb80-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> add<span class="op">(</span>InObj1 x,</span>
<span id="cb80-5"><a href="#cb80-5" aria-hidden="true" tabindex="-1"></a>         InObj2 y,</span>
<span id="cb80-6"><a href="#cb80-6" aria-hidden="true" tabindex="-1"></a>         OutObj z<span class="op">)</span>;</span>
<span id="cb80-7"><a href="#cb80-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb80-8"><a href="#cb80-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb80-9"><a href="#cb80-9" aria-hidden="true" tabindex="-1"></a>         <em>in-object</em> InObj1,</span>
<span id="cb80-10"><a href="#cb80-10" aria-hidden="true" tabindex="-1"></a>         <em>in-object</em> InObj2,</span>
<span id="cb80-11"><a href="#cb80-11" aria-hidden="true" tabindex="-1"></a>         <em>out-object</em> OutObj<span class="op">&gt;</span></span>
<span id="cb80-12"><a href="#cb80-12" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> add<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb80-13"><a href="#cb80-13" aria-hidden="true" tabindex="-1"></a>         InObj1 x,</span>
<span id="cb80-14"><a href="#cb80-14" aria-hidden="true" tabindex="-1"></a>         InObj2 y,</span>
<span id="cb80-15"><a href="#cb80-15" aria-hidden="true" tabindex="-1"></a>         OutObj z<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xAXPY</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em> For all <code>r</code> in 0, 1, …,
<code>x.rank()</code> - 1,</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>x.extent(r)</code> equals <code>z.extent(r)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>y.extent(r)</code> equals <code>z.extent(r)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> <code>x.rank()</code>, <code>y.rank()</code>, and
<code>z.rank()</code> are all equal.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em> For all <code>r</code> in 0, 1, …,
<code>x.rank()</code> - 1,</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> if
neither <code>x.static_extent(r)</code> nor
<code>z.static_extent(r)</code> equals <code>dynamic_extent</code>, then
<code>x.static_extent(r)</code> equals <code>z.static_extent(r)</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> if
neither <code>y.static_extent(r)</code> nor
<code>z.static_extent(r)</code> equals <code>dynamic_extent</code>, then
<code>y.static_extent(r)</code> equals
<code>z.static_extent(r)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span> if
neither <code>x.static_extent(r)</code> nor
<code>y.static_extent(r)</code> equals <code>dynamic_extent</code>, then
<code>x.static_extent(r)</code> equals
<code>y.static_extent(r)</code>;</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects</em>: Computes <span class="math inline"><em>z</em></span>
such that <span class="math inline"><em>z</em> = <em>x</em> + <em>y</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Remarks:</em> <code>z</code> may refer to the same vector as
<code>x</code> or <code>y</code>.</p>
<h4 data-number="16.10.2.6" id="dot-product-of-two-vectors-linalg.algs.blas1.dot"><span class="header-section-number">16.10.2.6</span> Dot product of two
vectors [linalg.algs.blas1.dot]<a href="#dot-product-of-two-vectors-linalg.algs.blas1.dot" class="self-link"></a></h4>
<h5 data-number="16.10.2.6.1" id="nonconjugated-dot-product-of-two-vectors-linalg.algs.blas1.dot.dotu"><span class="header-section-number">16.10.2.6.1</span> Nonconjugated dot
product of two vectors [linalg.algs.blas1.dot.dotu]<a href="#nonconjugated-dot-product-of-two-vectors-linalg.algs.blas1.dot.dotu" class="self-link"></a></h5>
<p><i>[Note:</i> The functions in this section correspond to the BLAS
functions <code>xDOT</code> (for real element types) and
<code>xDOTU</code> (for complex element types). <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Nonconjugated dot product with specified result type</p>
<div class="sourceCode" id="cb81"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb81-1"><a href="#cb81-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb81-2"><a href="#cb81-2" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb81-3"><a href="#cb81-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb81-4"><a href="#cb81-4" aria-hidden="true" tabindex="-1"></a>T dot<span class="op">(</span>InVec1 v1,</span>
<span id="cb81-5"><a href="#cb81-5" aria-hidden="true" tabindex="-1"></a>      InVec2 v2,</span>
<span id="cb81-6"><a href="#cb81-6" aria-hidden="true" tabindex="-1"></a>      T init<span class="op">)</span>;</span>
<span id="cb81-7"><a href="#cb81-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb81-8"><a href="#cb81-8" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb81-9"><a href="#cb81-9" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb81-10"><a href="#cb81-10" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb81-11"><a href="#cb81-11" aria-hidden="true" tabindex="-1"></a>T dot<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb81-12"><a href="#cb81-12" aria-hidden="true" tabindex="-1"></a>      InVec1 v1,</span>
<span id="cb81-13"><a href="#cb81-13" aria-hidden="true" tabindex="-1"></a>      InVec2 v2,</span>
<span id="cb81-14"><a href="#cb81-14" aria-hidden="true" tabindex="-1"></a>      T init<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Preconditions:</em> <code>v1.extent(0)</code> equals
<code>v2.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em> If neither <code>v1.static_extent(0)</code> nor
<code>v2.static_extent(0)</code> equals <code>dynamic_extent</code>,
then <code>v1.static_extent(0)</code> equals
<code>v2.static_extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em> Let <code>N</code> be <code>v1.extent(0)</code>. If
<code>N</code> is zero, returns <code>init</code>, else returns
<em>GENERALIZED_SUM</em>(<code>plus&lt;&gt;()</code>, <code>init</code>,
<code>v1[0]*v2[0]</code>, …, <code>v1[N-1]*v2[N-1]</code>).</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Remarks:</em> If <code>InVec1::value_type</code>,
<code>InVec2::value_type</code>, and <code>T</code> are all
floating-point types or complex versions thereof, and if <code>T</code>
has higher precision than <code>InVec1::value_type</code> or
<code>InVec2::value_type</code>, then intermediate terms in the sum use
<code>T</code>’s precision or greater.</p>
<p><i>[Note:</i> Like <code>reduce</code>, <code>dot</code> applies
binary <code>operator+</code> in an unspecified order. This may yield a
nondeterministic result for non-associative or non-commutative
<code>operator+</code> such as floating-point addition. However,
implementations may perform extra work to make the result deterministic.
They may do so for all <code>dot</code> overloads, or just for specific
<code>ExecutionPolicy</code> types. <i>– end note]</i></p>
<p><i>[Note:</i> Users can get <code>xDOTC</code> behavior by giving the
first argument as the result of <code>conjugated</code>. Alternately,
they can use the shortcut <code>dotc</code> below. <i>– end
note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
Nonconjugated dot product with default result type</p>
<div class="sourceCode" id="cb82"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb82-1"><a href="#cb82-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb82-2"><a href="#cb82-2" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2<span class="op">&gt;</span></span>
<span id="cb82-3"><a href="#cb82-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dot<span class="op">(</span>InVec1 v1,</span>
<span id="cb82-4"><a href="#cb82-4" aria-hidden="true" tabindex="-1"></a>         InVec2 v2<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb82-5"><a href="#cb82-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb82-6"><a href="#cb82-6" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb82-7"><a href="#cb82-7" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2<span class="op">&gt;</span></span>
<span id="cb82-8"><a href="#cb82-8" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dot<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb82-9"><a href="#cb82-9" aria-hidden="true" tabindex="-1"></a>         InVec1 v1,</span>
<span id="cb82-10"><a href="#cb82-10" aria-hidden="true" tabindex="-1"></a>         InVec2 v2<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Effects:</em> Let <code>T</code> be
<code>decltype(declval&lt;typename InVec1::value_type&gt;() * declval&lt;typename InVec2::value_type&gt;())</code>.
Then, the two-parameter overload is equivalent to
<code>dot(v1, v2, T{});</code>, and the three-parameter overload is
equivalent to <code>dot(exec, v1, v2, T{});</code>.</p>
<h5 data-number="16.10.2.6.2" id="conjugated-dot-product-of-two-vectors-linalg.algs.blas1.dot.dotc"><span class="header-section-number">16.10.2.6.2</span> Conjugated dot product
of two vectors [linalg.algs.blas1.dot.dotc]<a href="#conjugated-dot-product-of-two-vectors-linalg.algs.blas1.dot.dotc" class="self-link"></a></h5>
<p><i>[Note:</i> The functions in this section correspond to the BLAS
functions <code>xDOT</code> (for real element types) and
<code>xDOTC</code> (for complex element types).</p>
<p><code>dotc</code> exists to give users reasonable default inner
product behavior for both real and complex element types. <i>– end
note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Conjugated dot product with specified result type</p>
<div class="sourceCode" id="cb83"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb83-1"><a href="#cb83-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb83-2"><a href="#cb83-2" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb83-3"><a href="#cb83-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb83-4"><a href="#cb83-4" aria-hidden="true" tabindex="-1"></a>T dotc<span class="op">(</span>InVec1 v1,</span>
<span id="cb83-5"><a href="#cb83-5" aria-hidden="true" tabindex="-1"></a>       InVec2 v2,</span>
<span id="cb83-6"><a href="#cb83-6" aria-hidden="true" tabindex="-1"></a>       T init<span class="op">)</span>;</span>
<span id="cb83-7"><a href="#cb83-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb83-8"><a href="#cb83-8" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb83-9"><a href="#cb83-9" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb83-10"><a href="#cb83-10" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb83-11"><a href="#cb83-11" aria-hidden="true" tabindex="-1"></a>T dotc<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb83-12"><a href="#cb83-12" aria-hidden="true" tabindex="-1"></a>       InVec1 v1,</span>
<span id="cb83-13"><a href="#cb83-13" aria-hidden="true" tabindex="-1"></a>       InVec2 v2,</span>
<span id="cb83-14"><a href="#cb83-14" aria-hidden="true" tabindex="-1"></a>       T init<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> The three-argument overload is equivalent to
<code>dot(conjugated(v1), v2, init);</code>. The four-argument overload
is equivalent to <code>dot(exec, conjugated(v1), v2, init);</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
Conjugated dot product with default result type</p>
<div class="sourceCode" id="cb84"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb84-1"><a href="#cb84-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb84-2"><a href="#cb84-2" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2<span class="op">&gt;</span></span>
<span id="cb84-3"><a href="#cb84-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dotc<span class="op">(</span>InVec1 v1,</span>
<span id="cb84-4"><a href="#cb84-4" aria-hidden="true" tabindex="-1"></a>          InVec2 v2<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb84-5"><a href="#cb84-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb84-6"><a href="#cb84-6" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb84-7"><a href="#cb84-7" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2<span class="op">&gt;</span></span>
<span id="cb84-8"><a href="#cb84-8" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dotc<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb84-9"><a href="#cb84-9" aria-hidden="true" tabindex="-1"></a>          InVec1 v1,</span>
<span id="cb84-10"><a href="#cb84-10" aria-hidden="true" tabindex="-1"></a>          InVec2 v2<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em> Let <code>T</code> be
<code>decltype(</code><em><code>conj-if-needed</code></em><code>(declval&lt;typename InVec1::value_type&gt;()]) * declval&lt;typename InVec2::value_type&gt;())</code>.
Then, the two-parameter overload is equivalent to
<code>dotc(v1, v2, T{});</code>, and the three-parameter overload is
equivalent to <code>dotc(exec, v1, v2, T{});</code>.</p>
<h4 data-number="16.10.2.7" id="scaled-sum-of-squares-of-a-vectors-elements-linalg.algs.blas1.ssq"><span class="header-section-number">16.10.2.7</span> Scaled sum of squares of
a vector’s elements [linalg.algs.blas1.ssq]<a href="#scaled-sum-of-squares-of-a-vectors-elements-linalg.algs.blas1.ssq" class="self-link"></a></h4>
<div class="sourceCode" id="cb85"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb85-1"><a href="#cb85-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb85-2"><a href="#cb85-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> sum_of_squares_result <span class="op">{</span></span>
<span id="cb85-3"><a href="#cb85-3" aria-hidden="true" tabindex="-1"></a>  T scaling_factor;</span>
<span id="cb85-4"><a href="#cb85-4" aria-hidden="true" tabindex="-1"></a>  T scaled_sum_of_squares;</span>
<span id="cb85-5"><a href="#cb85-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb85-6"><a href="#cb85-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec,</span>
<span id="cb85-7"><a href="#cb85-7" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb85-8"><a href="#cb85-8" aria-hidden="true" tabindex="-1"></a>sum_of_squares_result<span class="op">&lt;</span>T<span class="op">&gt;</span> vector_sum_of_squares<span class="op">(</span></span>
<span id="cb85-9"><a href="#cb85-9" aria-hidden="true" tabindex="-1"></a>  InVec v,</span>
<span id="cb85-10"><a href="#cb85-10" aria-hidden="true" tabindex="-1"></a>  sum_of_squares_result<span class="op">&lt;</span>T<span class="op">&gt;</span> init<span class="op">)</span>;</span>
<span id="cb85-11"><a href="#cb85-11" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb85-12"><a href="#cb85-12" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb85-13"><a href="#cb85-13" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb85-14"><a href="#cb85-14" aria-hidden="true" tabindex="-1"></a>sum_of_squares_result<span class="op">&lt;</span>T<span class="op">&gt;</span> vector_sum_of_squares<span class="op">(</span></span>
<span id="cb85-15"><a href="#cb85-15" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb85-16"><a href="#cb85-16" aria-hidden="true" tabindex="-1"></a>  InVec v,</span>
<span id="cb85-17"><a href="#cb85-17" aria-hidden="true" tabindex="-1"></a>  sum_of_squares_result<span class="op">&lt;</span>T<span class="op">&gt;</span> init<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the LAPACK function
<code>xLASSQ</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>T</code> shall be <em>Cpp17MoveConstructible</em> and
<em>Cpp17LessThanComparable</em>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>abs(x[0])</code> shall be convertible to <code>T</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> For all <code>i</code> in the domain of
<code>v</code>, and for <code>f</code> and <code>ssq</code> of type
<code>T</code>, the expression
<code>ssq = ssq + (abs(x[i]) / f)*(abs(x[i]) / f)</code> is well
formed.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Effects:</em> Returns two values:</p>
<ul>
<li><p><code>scaling_factor</code>: the maximum of
<code>init.scaling_factor</code> and <code>abs(x[i])</code> for all
<code>i</code> in the domain of <code>v</code>; and</p></li>
<li><p><code>scaled_sum_of_squares</code>: a value such that
<code>scaling_factor * scaling_factor * scaled_sum_of_squares</code>
equals the sum of squares of <code>abs(x[i])</code> for all
<code>i</code> in the domain of <code>v</code>, plus
<code>init.scaling_factor * init.scaling_factor * init.scaled_sum_of_squares</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Remarks:</em> If <code>InVec::value_type</code> is either a
floating-point type or <code>complex&lt;R&gt;</code> for some
floating-point type <code>R</code>, and if <code>T</code> is a
floating-point type, then</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> if
<code>T</code> has higher precision than <code>InVec::value_type</code>,
then intermediate terms in the sum use <code>T</code>’s precision or
greater; and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> any
guarantees regarding overflow and underflow of
<code>vector_sum_of_squares</code> are implementation-defined.</p></li>
</ul>
<h4 data-number="16.10.2.8" id="euclidean-norm-of-a-vector-linalg.algs.blas1.nrm2"><span class="header-section-number">16.10.2.8</span> Euclidean norm of a
vector [linalg.algs.blas1.nrm2]<a href="#euclidean-norm-of-a-vector-linalg.algs.blas1.nrm2" class="self-link"></a></h4>
<h5 data-number="16.10.2.8.1" id="euclidean-norm-with-specified-result-type"><span class="header-section-number">16.10.2.8.1</span> Euclidean norm with
specified result type<a href="#euclidean-norm-with-specified-result-type" class="self-link"></a></h5>
<div class="sourceCode" id="cb86"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb86-1"><a href="#cb86-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec,</span>
<span id="cb86-2"><a href="#cb86-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb86-3"><a href="#cb86-3" aria-hidden="true" tabindex="-1"></a>T vector_norm2<span class="op">(</span>InVec v,</span>
<span id="cb86-4"><a href="#cb86-4" aria-hidden="true" tabindex="-1"></a>               T init<span class="op">)</span>;</span>
<span id="cb86-5"><a href="#cb86-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb86-6"><a href="#cb86-6" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb86-7"><a href="#cb86-7" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb86-8"><a href="#cb86-8" aria-hidden="true" tabindex="-1"></a>T vector_norm2<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb86-9"><a href="#cb86-9" aria-hidden="true" tabindex="-1"></a>               InVec v,</span>
<span id="cb86-10"><a href="#cb86-10" aria-hidden="true" tabindex="-1"></a>               T init<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xNRM2</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em>
<code>init + abs(declval&lt;InVec::value_type&gt;())*abs(declval&lt;InVec::value_type&gt;())</code>
shall be convertible to <code>T</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> Returns the square root of the sum of squares of
(<code>init</code> and the absolute values of the elements of
<code>A</code>). <i>[Note:</i> For <code>init</code> equal to zero, this
is the Euclidean norm (also called 2-norm) of the vector
<code>v</code>.</p>
<p>This description does not imply a recommended implementation for
floating-point types. See <em>Remarks</em> below. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Remarks:</em> If <code>InVec::value_type</code> is a floating-point
type or a complex version thereof, and if <code>T</code> is a
floating-point type, then</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> if
<code>T</code> has higher precision than <code>InVec::value_type</code>,
then intermediate terms in the sum use <code>T</code>’s precision or
greater; and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> any
guarantees regarding overflow and underflow of <code>vector_norm2</code>
are implementation-defined.</p></li>
</ul>
<p><i>[Note:</i> The <code>abs</code> function is invoked via
unqualified lookup.</p>
<p>A suggested implementation of this function for floating-point types
<code>T</code> would use the <code>scaled_sum_of_squares</code> result
from
<code>vector_sum_of_squares(x, {.scaling_factor=1.0, .scaled_sum_of_squares=init})</code>.
<i>– end note]</i></p>
<h5 data-number="16.10.2.8.2" id="euclidean-norm-with-default-result-type"><span class="header-section-number">16.10.2.8.2</span> Euclidean norm with
default result type<a href="#euclidean-norm-with-default-result-type" class="self-link"></a></h5>
<div class="sourceCode" id="cb87"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb87-1"><a href="#cb87-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec<span class="op">&gt;</span></span>
<span id="cb87-2"><a href="#cb87-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> vector_norm2<span class="op">(</span>InVec v<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb87-3"><a href="#cb87-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb87-4"><a href="#cb87-4" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec<span class="op">&gt;</span></span>
<span id="cb87-5"><a href="#cb87-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> vector_norm2<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb87-6"><a href="#cb87-6" aria-hidden="true" tabindex="-1"></a>                  InVec v<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Let <code>T</code> be
<code>decltype(abs(declval&lt;typename InVec::value_type&gt;()) * abs(declval&lt;typename InVec::value_type&gt;()))</code>.
Then, the one-parameter overload is equivalent to
<code>vector_norm2(v, T{});</code>, and the two-parameter overload is
equivalent to <code>vector_norm2(exec, v, T{});</code>.</p>
<h4 data-number="16.10.2.9" id="sum-of-absolute-values-of-vector-elements-linalg.algs.blas1.asum"><span class="header-section-number">16.10.2.9</span> Sum of absolute values of
vector elements [linalg.algs.blas1.asum]<a href="#sum-of-absolute-values-of-vector-elements-linalg.algs.blas1.asum" class="self-link"></a></h4>
<h5 data-number="16.10.2.9.1" id="sum-of-absolute-values-with-specified-result-type"><span class="header-section-number">16.10.2.9.1</span> Sum of absolute values
with specified result type<a href="#sum-of-absolute-values-with-specified-result-type" class="self-link"></a></h5>
<div class="sourceCode" id="cb88"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb88-1"><a href="#cb88-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec,</span>
<span id="cb88-2"><a href="#cb88-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb88-3"><a href="#cb88-3" aria-hidden="true" tabindex="-1"></a>T vector_abs_sum<span class="op">(</span>InVec v,</span>
<span id="cb88-4"><a href="#cb88-4" aria-hidden="true" tabindex="-1"></a>                 T init<span class="op">)</span>;</span>
<span id="cb88-5"><a href="#cb88-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb88-6"><a href="#cb88-6" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb88-7"><a href="#cb88-7" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb88-8"><a href="#cb88-8" aria-hidden="true" tabindex="-1"></a>T vector_abs_sum<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb88-9"><a href="#cb88-9" aria-hidden="true" tabindex="-1"></a>                 InVec v,</span>
<span id="cb88-10"><a href="#cb88-10" aria-hidden="true" tabindex="-1"></a>                 T init<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> This function corresponds to the BLAS functions
<code>SASUM</code>, <code>DASUM</code>, <code>CSASUM</code>, and
<code>DZASUM</code>. The different behavior for complex element types is
based on the observation that this lower-cost approximation of the
one-norm serves just as well as the actual one-norm for many linear
algebra algorithms in practice. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Constraints:</em>
<code>decltype(init + abs(declval&lt;typename InVec::value_type&gt;()))</code>
and
<code>decltype(init + abs(declval&lt;typename InVec::value_type&gt;()))</code>
are both convertible to <code>T</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> Let <code>N</code> be <code>v.extent(0)</code>:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> If
<code>N</code> is zero, returns <code>init</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
else, if <code>typename InVec::value_type</code> is
<code>complex&lt;R&gt;</code> for some <code>R</code>, then returns
<em>GENERALIZED_SUM</em>(<code>plus&lt;&gt;()</code>, <code>init</code>,
<code>abs(real(v[0])) + abs(imag(v[0]))</code>, …,
<code>abs(real(v[N-1])) + abs(imag(v[N-1]))</code>).</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
else, returns <em>GENERALIZED_SUM</em>(<code>plus&lt;&gt;()</code>,
<code>init</code>, <code>abs(v[0])</code>, …,
<code>abs(v[N-1])</code>).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Remarks:</em> If <code>InVec::value_type</code> is a floating-point
type or a complex version thereof, if <code>T</code> is a floating-point
type, and if <code>T</code> has higher precision than
<code>InVec::value_type</code>, then intermediate terms in the sum use
<code>T</code>’s precision or greater.</p>
<p><i>[Note:</i> The <code>abs</code>, <code>real</code>, and
<code>imag</code> functions are invoked via unqualified lookup. <i>– end
note]</i></p>
<h5 data-number="16.10.2.9.2" id="sum-of-absolute-values-with-default-result-type"><span class="header-section-number">16.10.2.9.2</span> Sum of absolute values
with default result type<a href="#sum-of-absolute-values-with-default-result-type" class="self-link"></a></h5>
<div class="sourceCode" id="cb89"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb89-1"><a href="#cb89-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec<span class="op">&gt;</span></span>
<span id="cb89-2"><a href="#cb89-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> vector_abs_sum<span class="op">(</span>InVec v<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb89-3"><a href="#cb89-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb89-4"><a href="#cb89-4" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec<span class="op">&gt;</span></span>
<span id="cb89-5"><a href="#cb89-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> vector_abs_sum<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb89-6"><a href="#cb89-6" aria-hidden="true" tabindex="-1"></a>                    InVec v<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Let <code>T</code> be
<code>typename InVec::value_type</code>. Then, the one-parameter
overload is equivalent to <code>vector_abs_sum(v, T{});</code>, and the
two-parameter overload is equivalent to
<code>vector_abs_sum(exec, v, T{});</code>.</p>
<h4 data-number="16.10.2.10" id="index-of-maximum-absolute-value-of-vector-elements-linalg.algs.blas1.iamax"><span class="header-section-number">16.10.2.10</span> Index of maximum
absolute value of vector elements [linalg.algs.blas1.iamax]<a href="#index-of-maximum-absolute-value-of-vector-elements-linalg.algs.blas1.iamax" class="self-link"></a></h4>
<div class="sourceCode" id="cb90"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb90-1"><a href="#cb90-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec<span class="op">&gt;</span></span>
<span id="cb90-2"><a href="#cb90-2" aria-hidden="true" tabindex="-1"></a><span class="kw">typename</span> InVec<span class="op">::</span>size_type idx_abs_max<span class="op">(</span>InVec v<span class="op">)</span>;</span>
<span id="cb90-3"><a href="#cb90-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb90-4"><a href="#cb90-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb90-5"><a href="#cb90-5" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec<span class="op">&gt;</span></span>
<span id="cb90-6"><a href="#cb90-6" aria-hidden="true" tabindex="-1"></a><span class="kw">typename</span> InVec<span class="op">::</span>size_type idx_abs_max<span class="op">(</span></span>
<span id="cb90-7"><a href="#cb90-7" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb90-8"><a href="#cb90-8" aria-hidden="true" tabindex="-1"></a>  InVec v<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>IxAMAX</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em> For <code>i</code> in the domain of
<code>v</code>, let <code>abs_value_type</code> be
<code>decltype(v[i])</code>; then, <code>abs_value_type</code> shall be
<em>Cpp17LessThanComparable</em>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> Returns the index (in the domain of <code>v</code>) of
the first element of <code>v</code> having largest absolute value. If
<code>v</code> has zero elements, then returns
<code>numeric_limits&lt;typename InVec::size_type&gt;::max()</code>.</p>
<p><i>[Note:</i> The <code>abs</code> function is invoked via
unqualified lookup. <i>– end note]</i></p>
<h4 data-number="16.10.2.11" id="frobenius-norm-of-a-matrix-linalg.algs.blas1.matfrobnorm"><span class="header-section-number">16.10.2.11</span> Frobenius norm of a
matrix [linalg.algs.blas1.matfrobnorm]<a href="#frobenius-norm-of-a-matrix-linalg.algs.blas1.matfrobnorm" class="self-link"></a></h4>
<h5 data-number="16.10.2.11.1" id="frobenius-norm-with-specified-result-type"><span class="header-section-number">16.10.2.11.1</span> Frobenius norm with
specified result type<a href="#frobenius-norm-with-specified-result-type" class="self-link"></a></h5>
<div class="sourceCode" id="cb91"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb91-1"><a href="#cb91-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb91-2"><a href="#cb91-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb91-3"><a href="#cb91-3" aria-hidden="true" tabindex="-1"></a>T matrix_frob_norm<span class="op">(</span></span>
<span id="cb91-4"><a href="#cb91-4" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb91-5"><a href="#cb91-5" aria-hidden="true" tabindex="-1"></a>  T init<span class="op">)</span>;</span>
<span id="cb91-6"><a href="#cb91-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb91-7"><a href="#cb91-7" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb91-8"><a href="#cb91-8" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb91-9"><a href="#cb91-9" aria-hidden="true" tabindex="-1"></a>T matrix_frob_norm<span class="op">(</span></span>
<span id="cb91-10"><a href="#cb91-10" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb91-11"><a href="#cb91-11" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb91-12"><a href="#cb91-12" aria-hidden="true" tabindex="-1"></a>  T init<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em>
<code>init + abs(declval&lt;InMat::value_type&gt;())*abs(declval&lt;InMat::value_type&gt;())</code>
shall be convertible to <code>T</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> Returns the square root of the sum of squares of
<code>init</code> and the absolute values of the elements of
<code>A</code>. <i>[Note:</i> For <code>init</code> equal to zero, this
is the Frobenius norm of the matrix <code>A</code>.</p>
<p>This description does not imply a recommended implementation for
floating-point types. See <em>Remarks</em> below. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Remarks:</em> If <code>InMat::value_type</code> is a floating-point
type or <code>complex&lt;R&gt;</code> for some floating-point type
<code>R</code>, and if <code>T</code> is a floating-point type, then</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> if
<code>T</code> has higher precision than
<code>InMatype::value_type</code>, then intermediate terms in the sum
use <code>T</code>’s precision or greater; and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> any
guarantees regarding overflow and underflow of
<code>matrix_frob_norm</code> are implementation-defined.</p></li>
</ul>
<p><i>[Note:</i> The <code>abs</code> function is invoked via
unqualified lookup. <i>– end note]</i></p>
<h5 data-number="16.10.2.11.2" id="frobenius-norm-with-default-result-type"><span class="header-section-number">16.10.2.11.2</span> Frobenius norm with
default result type<a href="#frobenius-norm-with-default-result-type" class="self-link"></a></h5>
<div class="sourceCode" id="cb92"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb92-1"><a href="#cb92-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat<span class="op">&gt;</span></span>
<span id="cb92-2"><a href="#cb92-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> matrix_frob_norm<span class="op">(</span></span>
<span id="cb92-3"><a href="#cb92-3" aria-hidden="true" tabindex="-1"></a>  InMat A<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb92-4"><a href="#cb92-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb92-5"><a href="#cb92-5" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat<span class="op">&gt;</span></span>
<span id="cb92-6"><a href="#cb92-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> matrix_frob_norm<span class="op">(</span></span>
<span id="cb92-7"><a href="#cb92-7" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb92-8"><a href="#cb92-8" aria-hidden="true" tabindex="-1"></a>  InMat A<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Let <code>T</code> be
<code>abs(declval&lt;V&gt;()) * abs(declval&lt;V&gt;())</code>, where
<code>V</code> names the type <code>typename InMat::value_type</code>.
Then, the one-parameter overload is equivalent to
<code>matrix_frob_norm(A, T{});</code>, and the two-parameter overload
is equivalent to <code>matrix_frob_norm(exec, A, T{});</code>.</p>
<h4 data-number="16.10.2.12" id="one-norm-of-a-matrix-linalg.algs.blas1.matonenorm"><span class="header-section-number">16.10.2.12</span> One norm of a matrix
[linalg.algs.blas1.matonenorm]<a href="#one-norm-of-a-matrix-linalg.algs.blas1.matonenorm" class="self-link"></a></h4>
<h5 data-number="16.10.2.12.1" id="one-norm-with-specified-result-type"><span class="header-section-number">16.10.2.12.1</span> One norm with
specified result type<a href="#one-norm-with-specified-result-type" class="self-link"></a></h5>
<div class="sourceCode" id="cb93"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb93-1"><a href="#cb93-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb93-2"><a href="#cb93-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb93-3"><a href="#cb93-3" aria-hidden="true" tabindex="-1"></a>T matrix_one_norm<span class="op">(</span></span>
<span id="cb93-4"><a href="#cb93-4" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb93-5"><a href="#cb93-5" aria-hidden="true" tabindex="-1"></a>  T init<span class="op">)</span>;</span>
<span id="cb93-6"><a href="#cb93-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb93-7"><a href="#cb93-7" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb93-8"><a href="#cb93-8" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb93-9"><a href="#cb93-9" aria-hidden="true" tabindex="-1"></a>T matrix_one_norm<span class="op">(</span></span>
<span id="cb93-10"><a href="#cb93-10" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb93-11"><a href="#cb93-11" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb93-12"><a href="#cb93-12" aria-hidden="true" tabindex="-1"></a>  T init<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Constraints:</em>
<code>abs(declval&lt;typename InMat::value_type&gt;())</code> is
convertible to <code>T</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> If
<code>A.extent(1)</code> is zero, returns <code>init</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
else, returns the sum of <code>init</code> and the one norm of the
matrix <span class="math inline"><em>A</em></span>.</p></li>
</ul>
<p><i>[Note:</i> The one norm of the matrix <code>A</code> is the
maximum over all columns of <code>A</code>, of the sum of the absolute
values of the elements of the column. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Remarks:</em> If <code>typename InMat::value_type</code> is a
floating-point type or <code>complex&lt;R&gt;</code> for some
floating-point type <code>R</code>, if <code>T</code> is a
floating-point type, and if <code>T</code> has higher precision than
<code>typename InMat::value_type</code>, then intermediate terms in each
sum use <code>T</code>’s precision or greater.</p>
<h5 data-number="16.10.2.12.2" id="one-norm-with-default-result-type"><span class="header-section-number">16.10.2.12.2</span> One norm with default
result type<a href="#one-norm-with-default-result-type" class="self-link"></a></h5>
<div class="sourceCode" id="cb94"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb94-1"><a href="#cb94-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat<span class="op">&gt;</span></span>
<span id="cb94-2"><a href="#cb94-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> matrix_one_norm<span class="op">(</span></span>
<span id="cb94-3"><a href="#cb94-3" aria-hidden="true" tabindex="-1"></a>  InMat A<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb94-4"><a href="#cb94-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb94-5"><a href="#cb94-5" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat<span class="op">&gt;</span></span>
<span id="cb94-6"><a href="#cb94-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> matrix_one_norm<span class="op">(</span></span>
<span id="cb94-7"><a href="#cb94-7" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb94-8"><a href="#cb94-8" aria-hidden="true" tabindex="-1"></a>  InMat A<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Let <code>T</code> be
<code>decltype(abs(declval&lt;typename InMat::value_type&gt;())</code>.
Then, the one-parameter overload is equivalent to
<code>matrix_one_norm(A, T{});</code>, and the two-parameter overload is
equivalent to <code>matrix_one_norm(exec, A, T{});</code>.</p>
<p><i>[Note:</i> The <code>abs</code> function is invoked via
unqualified lookup. <i>– end note]</i></p>
<h4 data-number="16.10.2.13" id="infinity-norm-of-a-matrix-linalg.algs.blas1.matinfnorm"><span class="header-section-number">16.10.2.13</span> Infinity norm of a
matrix [linalg.algs.blas1.matinfnorm]<a href="#infinity-norm-of-a-matrix-linalg.algs.blas1.matinfnorm" class="self-link"></a></h4>
<h5 data-number="16.10.2.13.1" id="infinity-norm-with-specified-result-type"><span class="header-section-number">16.10.2.13.1</span> Infinity norm with
specified result type<a href="#infinity-norm-with-specified-result-type" class="self-link"></a></h5>
<div class="sourceCode" id="cb95"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb95-1"><a href="#cb95-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb95-2"><a href="#cb95-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb95-3"><a href="#cb95-3" aria-hidden="true" tabindex="-1"></a>T matrix_inf_norm<span class="op">(</span></span>
<span id="cb95-4"><a href="#cb95-4" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb95-5"><a href="#cb95-5" aria-hidden="true" tabindex="-1"></a>  T init<span class="op">)</span>;</span>
<span id="cb95-6"><a href="#cb95-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb95-7"><a href="#cb95-7" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb95-8"><a href="#cb95-8" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb95-9"><a href="#cb95-9" aria-hidden="true" tabindex="-1"></a>T matrix_inf_norm<span class="op">(</span></span>
<span id="cb95-10"><a href="#cb95-10" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb95-11"><a href="#cb95-11" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb95-12"><a href="#cb95-12" aria-hidden="true" tabindex="-1"></a>  T init<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em> <code>abs(A[0,0])</code> shall be convertible to
<code>T</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> If
<code>A.extent(0)</code> is zero, returns <code>init</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
else, returns the sum of <code>init</code> and the infinity norm of the
matrix <code>A</code>. The infinity norm of the matrix <code>A</code> is
the maximum over all rows of <code>A</code>, of the sum of the absolute
values of the elements of the row.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Remarks:</em> If <code>InMat::value_type</code> is a floating-point
type or <code>complex&lt;R&gt;</code> for some floating-point type
<code>R</code>, if <code>T</code> is a floating-point type, and if
<code>T</code> has higher precision than <code>InMat::value_type</code>,
then intermediate terms in each sum use <code>T</code>’s precision or
greater.</p>
<p><i>[Note:</i> The <code>abs</code> function is invoked via
unqualified lookup. <i>– end note]</i></p>
<h5 data-number="16.10.2.13.2" id="infinity-norm-with-default-result-type"><span class="header-section-number">16.10.2.13.2</span> Infinity norm with
default result type<a href="#infinity-norm-with-default-result-type" class="self-link"></a></h5>
<div class="sourceCode" id="cb96"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb96-1"><a href="#cb96-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat<span class="op">&gt;</span></span>
<span id="cb96-2"><a href="#cb96-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> matrix_inf_norm<span class="op">(</span></span>
<span id="cb96-3"><a href="#cb96-3" aria-hidden="true" tabindex="-1"></a>  InMat A<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span>
<span id="cb96-4"><a href="#cb96-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb96-5"><a href="#cb96-5" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat<span class="op">&gt;</span></span>
<span id="cb96-6"><a href="#cb96-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> matrix_inf_norm<span class="op">(</span></span>
<span id="cb96-7"><a href="#cb96-7" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb96-8"><a href="#cb96-8" aria-hidden="true" tabindex="-1"></a>  InMat A<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see-below */</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Let <code>T</code> be
<code>decltype(abs(declval&lt;typename InMat::value_type&gt;())</code>.
Then, the one-parameter overload is equivalent to
<code>matrix_inf_norm(A, T{});</code>, and the two-parameter overload is
equivalent to <code>matrix_inf_norm(exec, A, T{});</code>.</p>
<h3 data-number="16.10.3" id="blas-2-functions-linalg.algs.blas2"><span class="header-section-number">16.10.3</span> BLAS 2 functions
[linalg.algs.blas2]<a href="#blas-2-functions-linalg.algs.blas2" class="self-link"></a></h3>
<h4 data-number="16.10.3.1" id="general-matrix-vector-product-linalg.algs.blas2.gemv"><span class="header-section-number">16.10.3.1</span> General matrix-vector
product [linalg.algs.blas2.gemv]<a href="#general-matrix-vector-product-linalg.algs.blas2.gemv" class="self-link"></a></h4>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xGEMV</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following requirements apply to all functions in this section.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>A.extent(1)</code> equals <code>x.extent(0)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>A.extent(0)</code> equals <code>y.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<code>y.extent(0)</code> equals <code>z.extent(0)</code> (if
applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
neither <code>A.static_extent(1)</code> nor
<code>x.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>x.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>y.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>y.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span> If
neither <code>y.static_extent(0)</code> nor
<code>z.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>y.static_extent(0)</code> equals <code>z.static_extent(0)</code>
(if applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Complexity:</em> All algorithms in this Clause with
<code>mdspan</code> parameters perform a count of <code>mdspan</code>
array accesses and arithmetic operations that is linear in
<code>x.extent(0)</code> times <code>A.extent(1)</code>.</p>
<h5 data-number="16.10.3.1.1" id="overwriting-matrix-vector-product"><span class="header-section-number">16.10.3.1.1</span> Overwriting
matrix-vector product<a href="#overwriting-matrix-vector-product" class="self-link"></a></h5>
<div class="sourceCode" id="cb97"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb97-1"><a href="#cb97-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb97-2"><a href="#cb97-2" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb97-3"><a href="#cb97-3" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb97-4"><a href="#cb97-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_vector_product<span class="op">(</span>InMat A,</span>
<span id="cb97-5"><a href="#cb97-5" aria-hidden="true" tabindex="-1"></a>                           InVec x,</span>
<span id="cb97-6"><a href="#cb97-6" aria-hidden="true" tabindex="-1"></a>                           OutVec y<span class="op">)</span>;</span>
<span id="cb97-7"><a href="#cb97-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb97-8"><a href="#cb97-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb97-9"><a href="#cb97-9" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb97-10"><a href="#cb97-10" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb97-11"><a href="#cb97-11" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb97-12"><a href="#cb97-12" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_vector_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb97-13"><a href="#cb97-13" aria-hidden="true" tabindex="-1"></a>                           InMat A,</span>
<span id="cb97-14"><a href="#cb97-14" aria-hidden="true" tabindex="-1"></a>                           InVec x,</span>
<span id="cb97-15"><a href="#cb97-15" aria-hidden="true" tabindex="-1"></a>                           OutVec y<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>y</em></span>
such that <span class="math inline"><em>y</em> = <em>A</em><em>x</em></span>.</p>
<p>[<em>Example:</em></p>
<div class="sourceCode" id="cb98"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb98-1"><a href="#cb98-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">size_t</span> num_rows <span class="op">=</span> <span class="dv">5</span>;</span>
<span id="cb98-2"><a href="#cb98-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">size_t</span> num_cols <span class="op">=</span> <span class="dv">6</span>;</span>
<span id="cb98-3"><a href="#cb98-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb98-4"><a href="#cb98-4" aria-hidden="true" tabindex="-1"></a><span class="co">// y = 3.0 * A * x</span></span>
<span id="cb98-5"><a href="#cb98-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> scaled_matvec_1<span class="op">(</span></span>
<span id="cb98-6"><a href="#cb98-6" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, num_rows, num_cols<span class="op">&gt;&gt;</span> A,</span>
<span id="cb98-7"><a href="#cb98-7" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, num_cols<span class="op">&gt;&gt;</span> x,</span>
<span id="cb98-8"><a href="#cb98-8" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, num_rows<span class="op">&gt;&gt;</span> y<span class="op">)</span></span>
<span id="cb98-9"><a href="#cb98-9" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb98-10"><a href="#cb98-10" aria-hidden="true" tabindex="-1"></a>  matrix_vector_product<span class="op">(</span>scaled<span class="op">(</span><span class="fl">3.0</span>, A<span class="op">)</span>, x, y<span class="op">)</span>;</span>
<span id="cb98-11"><a href="#cb98-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb98-12"><a href="#cb98-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb98-13"><a href="#cb98-13" aria-hidden="true" tabindex="-1"></a><span class="co">// y = 3.0 * A * x + 2.0 * y</span></span>
<span id="cb98-14"><a href="#cb98-14" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> scaled_matvec_2<span class="op">(</span></span>
<span id="cb98-15"><a href="#cb98-15" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, num_rows, num_cols<span class="op">&gt;&gt;</span> A,</span>
<span id="cb98-16"><a href="#cb98-16" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, num_cols<span class="op">&gt;&gt;</span> x,</span>
<span id="cb98-17"><a href="#cb98-17" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, num_rows<span class="op">&gt;&gt;</span> y<span class="op">)</span></span>
<span id="cb98-18"><a href="#cb98-18" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb98-19"><a href="#cb98-19" aria-hidden="true" tabindex="-1"></a>  matrix_vector_product<span class="op">(</span>scaled<span class="op">(</span><span class="fl">3.0</span>, A<span class="op">)</span>, x,</span>
<span id="cb98-20"><a href="#cb98-20" aria-hidden="true" tabindex="-1"></a>                        scaled<span class="op">(</span><span class="fl">2.0</span>, y<span class="op">)</span>, y<span class="op">)</span>;</span>
<span id="cb98-21"><a href="#cb98-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb98-22"><a href="#cb98-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb98-23"><a href="#cb98-23" aria-hidden="true" tabindex="-1"></a><span class="co">// z = 7.0 times the transpose of A, times y</span></span>
<span id="cb98-24"><a href="#cb98-24" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> scaled_matvec_2<span class="op">(</span>mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, num_rows, num_cols<span class="op">&gt;&gt;</span> A,</span>
<span id="cb98-25"><a href="#cb98-25" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, num_rows<span class="op">&gt;&gt;</span> y,</span>
<span id="cb98-26"><a href="#cb98-26" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">double</span>, extents<span class="op">&lt;</span><span class="dt">size_t</span>, num_cols<span class="op">&gt;&gt;</span> z<span class="op">)</span></span>
<span id="cb98-27"><a href="#cb98-27" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb98-28"><a href="#cb98-28" aria-hidden="true" tabindex="-1"></a>  matrix_vector_product<span class="op">(</span>scaled<span class="op">(</span><span class="fl">7.0</span>, transposed<span class="op">(</span>A<span class="op">))</span>, y, z<span class="op">)</span>;</span>
<span id="cb98-29"><a href="#cb98-29" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>–<em>end example</em>]</p>
<h5 data-number="16.10.3.1.2" id="updating-matrix-vector-product"><span class="header-section-number">16.10.3.1.2</span> Updating matrix-vector
product<a href="#updating-matrix-vector-product" class="self-link"></a></h5>
<div class="sourceCode" id="cb99"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb99-1"><a href="#cb99-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb99-2"><a href="#cb99-2" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb99-3"><a href="#cb99-3" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb99-4"><a href="#cb99-4" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb99-5"><a href="#cb99-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_vector_product<span class="op">(</span>InMat A,</span>
<span id="cb99-6"><a href="#cb99-6" aria-hidden="true" tabindex="-1"></a>                           InVec1 x,</span>
<span id="cb99-7"><a href="#cb99-7" aria-hidden="true" tabindex="-1"></a>                           InVec2 y,</span>
<span id="cb99-8"><a href="#cb99-8" aria-hidden="true" tabindex="-1"></a>                           OutVec z<span class="op">)</span>;</span>
<span id="cb99-9"><a href="#cb99-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb99-10"><a href="#cb99-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb99-11"><a href="#cb99-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb99-12"><a href="#cb99-12" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb99-13"><a href="#cb99-13" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb99-14"><a href="#cb99-14" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb99-15"><a href="#cb99-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_vector_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb99-16"><a href="#cb99-16" aria-hidden="true" tabindex="-1"></a>                           InMat A,</span>
<span id="cb99-17"><a href="#cb99-17" aria-hidden="true" tabindex="-1"></a>                           InVec1 x,</span>
<span id="cb99-18"><a href="#cb99-18" aria-hidden="true" tabindex="-1"></a>                           InVec2 y,</span>
<span id="cb99-19"><a href="#cb99-19" aria-hidden="true" tabindex="-1"></a>                           OutVec z<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>z</em></span>
such that <span class="math inline"><em>z</em> = <em>y</em> + <em>A</em><em>x</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Remarks:</em> <code>y</code> and <code>z</code> may refer to the
same vector.</p>
<h4 data-number="16.10.3.2" id="symmetric-matrix-vector-product-linalg.algs.blas2.symv"><span class="header-section-number">16.10.3.2</span> Symmetric matrix-vector
product [linalg.algs.blas2.symv]<a href="#symmetric-matrix-vector-product-linalg.algs.blas2.symv" class="self-link"></a></h4>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xSYMV</code> and <code>xSPMV</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following requirements apply to all functions in this section.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>A.extent(1)</code> equals <code>x.extent(0)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<code>A.extent(0)</code> equals <code>y.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.4)</a></span>
<code>y.extent(0)</code> equals <code>z.extent(0)</code> (if
applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Constraints:</em></p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
<code>InMat</code> has <code>layout_blas_packed</code> layout, then the
layout’s <code>Triangle</code> template argument has the same type as
the function’s <code>Triangle</code> template argument.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>A.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>A.static_extent(1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> If
neither <code>A.static_extent(1)</code> nor
<code>x.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>x.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>y.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>y.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.4)</a></span> If
neither <code>y.static_extent(0)</code> nor
<code>z.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>y.static_extent(0)</code> equals <code>z.static_extent(0)</code>
(if applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Complexity:</em> All algorithms in this Clause with
<code>mdspan</code> parameters perform a count of <code>mdspan</code>
array accesses and arithmetic operations that is linear in
<code>x.extent(0)</code> times <code>A.extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Remarks:</em> The functions will only access the triangle of
<code>A</code> specified by the <code>Triangle</code> argument
<code>t</code>, and will interpret the value <code>A[i,j]</code> as
equal to <code>A[j,i]</code> for indices <code>i,j</code> in the domain
of <code>A</code> but outside the triangle specified by
<code>t</code>.</p>
<h5 data-number="16.10.3.2.1" id="overwriting-symmetric-matrix-vector-product"><span class="header-section-number">16.10.3.2.1</span> Overwriting symmetric
matrix-vector product<a href="#overwriting-symmetric-matrix-vector-product" class="self-link"></a></h5>
<div class="sourceCode" id="cb100"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb100-1"><a href="#cb100-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb100-2"><a href="#cb100-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb100-3"><a href="#cb100-3" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb100-4"><a href="#cb100-4" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb100-5"><a href="#cb100-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_vector_product<span class="op">(</span>InMat A,</span>
<span id="cb100-6"><a href="#cb100-6" aria-hidden="true" tabindex="-1"></a>                                     Triangle t,</span>
<span id="cb100-7"><a href="#cb100-7" aria-hidden="true" tabindex="-1"></a>                                     InVec x,</span>
<span id="cb100-8"><a href="#cb100-8" aria-hidden="true" tabindex="-1"></a>                                     OutVec y<span class="op">)</span>;</span>
<span id="cb100-9"><a href="#cb100-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb100-10"><a href="#cb100-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb100-11"><a href="#cb100-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb100-12"><a href="#cb100-12" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb100-13"><a href="#cb100-13" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb100-14"><a href="#cb100-14" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb100-15"><a href="#cb100-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_vector_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb100-16"><a href="#cb100-16" aria-hidden="true" tabindex="-1"></a>                                     InMat A,</span>
<span id="cb100-17"><a href="#cb100-17" aria-hidden="true" tabindex="-1"></a>                                     Triangle t,</span>
<span id="cb100-18"><a href="#cb100-18" aria-hidden="true" tabindex="-1"></a>                                     InVec x,</span>
<span id="cb100-19"><a href="#cb100-19" aria-hidden="true" tabindex="-1"></a>                                     OutVec y<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>y</em></span>
such that <span class="math inline"><em>y</em> = <em>A</em><em>x</em></span>.</p>
<h5 data-number="16.10.3.2.2" id="updating-symmetric-matrix-vector-product"><span class="header-section-number">16.10.3.2.2</span> Updating symmetric
matrix-vector product<a href="#updating-symmetric-matrix-vector-product" class="self-link"></a></h5>
<div class="sourceCode" id="cb101"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb101-1"><a href="#cb101-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb101-2"><a href="#cb101-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb101-3"><a href="#cb101-3" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb101-4"><a href="#cb101-4" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb101-5"><a href="#cb101-5" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb101-6"><a href="#cb101-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_vector_product<span class="op">(</span></span>
<span id="cb101-7"><a href="#cb101-7" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb101-8"><a href="#cb101-8" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb101-9"><a href="#cb101-9" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb101-10"><a href="#cb101-10" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb101-11"><a href="#cb101-11" aria-hidden="true" tabindex="-1"></a>  OutVec z<span class="op">)</span>;</span>
<span id="cb101-12"><a href="#cb101-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb101-13"><a href="#cb101-13" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb101-14"><a href="#cb101-14" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb101-15"><a href="#cb101-15" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb101-16"><a href="#cb101-16" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb101-17"><a href="#cb101-17" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb101-18"><a href="#cb101-18" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb101-19"><a href="#cb101-19" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_vector_product<span class="op">(</span></span>
<span id="cb101-20"><a href="#cb101-20" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb101-21"><a href="#cb101-21" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb101-22"><a href="#cb101-22" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb101-23"><a href="#cb101-23" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb101-24"><a href="#cb101-24" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb101-25"><a href="#cb101-25" aria-hidden="true" tabindex="-1"></a>  OutVec z<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>z</em></span>
such that <span class="math inline"><em>z</em> = <em>y</em> + <em>A</em><em>x</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Remarks:</em> <code>y</code> and <code>z</code> may refer to the
same vector.</p>
<h4 data-number="16.10.3.3" id="hermitian-matrix-vector-product-linalg.algs.blas2.hemv"><span class="header-section-number">16.10.3.3</span> Hermitian matrix-vector
product [linalg.algs.blas2.hemv]<a href="#hermitian-matrix-vector-product-linalg.algs.blas2.hemv" class="self-link"></a></h4>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xHEMV</code> and <code>xHPMV</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following requirements apply to all functions in this section.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>A.extent(1)</code> equals <code>x.extent(0)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<code>A.extent(0)</code> equals <code>y.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.4)</a></span>
<code>y.extent(0)</code> equals <code>z.extent(0)</code> (if
applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Constraints:</em></p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
<code>InMat</code> has <code>layout_blas_packed</code> layout, then the
layout’s <code>Triangle</code> template argument has the same type as
the function’s <code>Triangle</code> template argument.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>A.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>A.static_extent(1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> If
neither <code>A.static_extent(1)</code> nor
<code>x.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>x.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>y.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>y.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.4)</a></span> If
neither <code>y.static_extent(0)</code> nor
<code>z.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>y.static_extent(0)</code> equals <code>z.static_extent(0)</code>
(if applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Complexity:</em> All algorithms in this Clause with
<code>mdspan</code> parameters perform a count of <code>mdspan</code>
array accesses and arithmetic operations that is linear in
<code>x.extent(0)</code> times <code>A.extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Remarks:</em> The functions will only access the triangle of
<code>A</code> specified by the <code>Triangle</code> argument
<code>t</code>, and will interpret the value <code>A[i,j]</code> as
equal to <em><code>conj-if-needed</code></em><code>(A[j,i])</code> for
indices <code>i,j</code> in the domain of <code>A</code> but outside the
triangle specified by <code>t</code>.</p>
<h5 data-number="16.10.3.3.1" id="overwriting-hermitian-matrix-vector-product"><span class="header-section-number">16.10.3.3.1</span> Overwriting Hermitian
matrix-vector product<a href="#overwriting-hermitian-matrix-vector-product" class="self-link"></a></h5>
<div class="sourceCode" id="cb102"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb102-1"><a href="#cb102-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb102-2"><a href="#cb102-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb102-3"><a href="#cb102-3" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb102-4"><a href="#cb102-4" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb102-5"><a href="#cb102-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_vector_product<span class="op">(</span>InMat A,</span>
<span id="cb102-6"><a href="#cb102-6" aria-hidden="true" tabindex="-1"></a>                                     Triangle t,</span>
<span id="cb102-7"><a href="#cb102-7" aria-hidden="true" tabindex="-1"></a>                                     InVec x,</span>
<span id="cb102-8"><a href="#cb102-8" aria-hidden="true" tabindex="-1"></a>                                     OutVec y<span class="op">)</span>;</span>
<span id="cb102-9"><a href="#cb102-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb102-10"><a href="#cb102-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb102-11"><a href="#cb102-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb102-12"><a href="#cb102-12" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb102-13"><a href="#cb102-13" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb102-14"><a href="#cb102-14" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb102-15"><a href="#cb102-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_vector_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb102-16"><a href="#cb102-16" aria-hidden="true" tabindex="-1"></a>                                     InMat A,</span>
<span id="cb102-17"><a href="#cb102-17" aria-hidden="true" tabindex="-1"></a>                                     Triangle t,</span>
<span id="cb102-18"><a href="#cb102-18" aria-hidden="true" tabindex="-1"></a>                                     InVec x,</span>
<span id="cb102-19"><a href="#cb102-19" aria-hidden="true" tabindex="-1"></a>                                     OutVec y<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>y</em></span>
such that <span class="math inline"><em>y</em> = <em>A</em><em>x</em></span>.</p>
<h5 data-number="16.10.3.3.2" id="updating-hermitian-matrix-vector-product"><span class="header-section-number">16.10.3.3.2</span> Updating Hermitian
matrix-vector product<a href="#updating-hermitian-matrix-vector-product" class="self-link"></a></h5>
<div class="sourceCode" id="cb103"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb103-1"><a href="#cb103-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb103-2"><a href="#cb103-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb103-3"><a href="#cb103-3" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb103-4"><a href="#cb103-4" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb103-5"><a href="#cb103-5" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb103-6"><a href="#cb103-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_vector_product<span class="op">(</span>InMat A,</span>
<span id="cb103-7"><a href="#cb103-7" aria-hidden="true" tabindex="-1"></a>                                     Triangle t,</span>
<span id="cb103-8"><a href="#cb103-8" aria-hidden="true" tabindex="-1"></a>                                     InVec1 x,</span>
<span id="cb103-9"><a href="#cb103-9" aria-hidden="true" tabindex="-1"></a>                                     InVec2 y,</span>
<span id="cb103-10"><a href="#cb103-10" aria-hidden="true" tabindex="-1"></a>                                     OutVec z<span class="op">)</span>;</span>
<span id="cb103-11"><a href="#cb103-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb103-12"><a href="#cb103-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb103-13"><a href="#cb103-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb103-14"><a href="#cb103-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb103-15"><a href="#cb103-15" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb103-16"><a href="#cb103-16" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb103-17"><a href="#cb103-17" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb103-18"><a href="#cb103-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_vector_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb103-19"><a href="#cb103-19" aria-hidden="true" tabindex="-1"></a>                                     InMat A,</span>
<span id="cb103-20"><a href="#cb103-20" aria-hidden="true" tabindex="-1"></a>                                     Triangle t,</span>
<span id="cb103-21"><a href="#cb103-21" aria-hidden="true" tabindex="-1"></a>                                     InVec1 x,</span>
<span id="cb103-22"><a href="#cb103-22" aria-hidden="true" tabindex="-1"></a>                                     InVec2 y,</span>
<span id="cb103-23"><a href="#cb103-23" aria-hidden="true" tabindex="-1"></a>                                     OutVec z<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>z</em></span>
such that <span class="math inline"><em>z</em> = <em>y</em> + <em>A</em><em>x</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Remarks:</em> <code>y</code> and <code>z</code> may refer to the
same vector.</p>
<h4 data-number="16.10.3.4" id="triangular-matrix-vector-product-linalg.algs.blas2.trmv"><span class="header-section-number">16.10.3.4</span> Triangular matrix-vector
product [linalg.algs.blas2.trmv]<a href="#triangular-matrix-vector-product-linalg.algs.blas2.trmv" class="self-link"></a></h4>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xTRMV</code> and <code>xTPMV</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following requirements apply to all functions in this section.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>A.extent(0)</code> equals <code>y.extent(0)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<code>A.extent(1)</code> equals <code>x.extent(0)</code> (if
applicable), and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.4)</a></span>
<code>y.extent(0)</code> equals <code>z.extent(0)</code> (if
applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Constraints:</em> if <code>InMat</code> has
<code>layout_blas_packed</code> layout, then the layout’s
<code>Triangle</code> template argument has the same type as the
function’s <code>Triangle</code> template argument.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> if
neither <code>A.static_extent(0)</code> nor
<code>A.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>A.static_extent(1)</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> if
neither <code>A.static_extent(0)</code> nor
<code>y.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>y.static_extent(0)</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span> if
neither <code>A.static_extent(1)</code> nor
<code>x.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals <code>x.static_extent(0)</code>
(if applicable); and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.4)</a></span> if
neither <code>y.static_extent(0)</code> nor
<code>z.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>y.static_extent(0)</code> equals <code>z.static_extent(0)</code>
(if applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Complexity:</em> All algorithms in this Clause with
<code>mdspan</code> parameters perform a count of <code>mdspan</code>
array accesses and arithmetic operations that is linear in
<code>x.extent(0)</code> times <code>A.extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Remarks:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span> The
functions will only access the triangle of <code>A</code> specified by
the <code>Triangle</code> argument <code>t</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span> If
the <code>DiagonalStorage</code> template argument has type
<code>implicit_unit_diagonal_t</code>, then the functions will not
access the diagonal of <code>A</code>, and will interpret <code>A</code>
as if each of its diagonal elements behaves as a two-sided
multiplicative identity.</p></li>
</ul>
<h5 data-number="16.10.3.4.1" id="overwriting-triangular-matrix-vector-product-linalg.algs.blas2.trmv.ov"><span class="header-section-number">16.10.3.4.1</span> Overwriting triangular
matrix-vector product [linalg.algs.blas2.trmv.ov]<a href="#overwriting-triangular-matrix-vector-product-linalg.algs.blas2.trmv.ov" class="self-link"></a></h5>
<div class="sourceCode" id="cb104"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb104-1"><a href="#cb104-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb104-2"><a href="#cb104-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb104-3"><a href="#cb104-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb104-4"><a href="#cb104-4" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb104-5"><a href="#cb104-5" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb104-6"><a href="#cb104-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_product<span class="op">(</span></span>
<span id="cb104-7"><a href="#cb104-7" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb104-8"><a href="#cb104-8" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb104-9"><a href="#cb104-9" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb104-10"><a href="#cb104-10" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb104-11"><a href="#cb104-11" aria-hidden="true" tabindex="-1"></a>  OutVec y<span class="op">)</span>;</span>
<span id="cb104-12"><a href="#cb104-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb104-13"><a href="#cb104-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb104-14"><a href="#cb104-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb104-15"><a href="#cb104-15" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb104-16"><a href="#cb104-16" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb104-17"><a href="#cb104-17" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb104-18"><a href="#cb104-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_product<span class="op">(</span></span>
<span id="cb104-19"><a href="#cb104-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb104-20"><a href="#cb104-20" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb104-21"><a href="#cb104-21" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb104-22"><a href="#cb104-22" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb104-23"><a href="#cb104-23" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb104-24"><a href="#cb104-24" aria-hidden="true" tabindex="-1"></a>  OutVec y<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>y</em></span>
such that <span class="math inline"><em>y</em> = <em>A</em><em>x</em></span>.</p>
<h5 data-number="16.10.3.4.2" id="in-place-triangular-matrix-vector-product-linalg.algs.blas2.trmv.in-place"><span class="header-section-number">16.10.3.4.2</span> In-place triangular
matrix-vector product [linalg.algs.blas2.trmv.in-place]<a href="#in-place-triangular-matrix-vector-product-linalg.algs.blas2.trmv.in-place" class="self-link"></a></h5>
<div class="sourceCode" id="cb105"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb105-1"><a href="#cb105-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb105-2"><a href="#cb105-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb105-3"><a href="#cb105-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb105-4"><a href="#cb105-4" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec<span class="op">&gt;</span></span>
<span id="cb105-5"><a href="#cb105-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_product<span class="op">(</span></span>
<span id="cb105-6"><a href="#cb105-6" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb105-7"><a href="#cb105-7" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb105-8"><a href="#cb105-8" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb105-9"><a href="#cb105-9" aria-hidden="true" tabindex="-1"></a>  InOutVec y<span class="op">)</span>;</span>
<span id="cb105-10"><a href="#cb105-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb105-11"><a href="#cb105-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb105-12"><a href="#cb105-12" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb105-13"><a href="#cb105-13" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb105-14"><a href="#cb105-14" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec<span class="op">&gt;</span></span>
<span id="cb105-15"><a href="#cb105-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_product<span class="op">(</span></span>
<span id="cb105-16"><a href="#cb105-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb105-17"><a href="#cb105-17" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb105-18"><a href="#cb105-18" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb105-19"><a href="#cb105-19" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb105-20"><a href="#cb105-20" aria-hidden="true" tabindex="-1"></a>  InOutVec y<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> Performing this operation in place hinders
parallelization. However, other <code>ExecutionPolicy</code>-specific
optimizations, such as vectorization, are still possible. This is why
the <code>ExecutionPolicy</code> overload exists. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em> <code>A.extent(1)</code> equals
<code>y.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Mandates:</em> If neither <code>A.static_extent(1)</code> nor
<code>y.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>y.static_extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>y</em></span>
such that <span class="math inline"><em>y</em> = <em>A</em><em>x</em></span>.</p>
<h5 data-number="16.10.3.4.3" id="updating-triangular-matrix-vector-product-linalg.algs.blas2.trmv.up"><span class="header-section-number">16.10.3.4.3</span> Updating triangular
matrix-vector product [linalg.algs.blas2.trmv.up]<a href="#updating-triangular-matrix-vector-product-linalg.algs.blas2.trmv.up" class="self-link"></a></h5>
<div class="sourceCode" id="cb106"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb106-1"><a href="#cb106-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb106-2"><a href="#cb106-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb106-3"><a href="#cb106-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb106-4"><a href="#cb106-4" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb106-5"><a href="#cb106-5" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb106-6"><a href="#cb106-6" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb106-7"><a href="#cb106-7" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_product<span class="op">(</span>InMat A,</span>
<span id="cb106-8"><a href="#cb106-8" aria-hidden="true" tabindex="-1"></a>                                      Triangle t,</span>
<span id="cb106-9"><a href="#cb106-9" aria-hidden="true" tabindex="-1"></a>                                      DiagonalStorage d,</span>
<span id="cb106-10"><a href="#cb106-10" aria-hidden="true" tabindex="-1"></a>                                      InVec1 x,</span>
<span id="cb106-11"><a href="#cb106-11" aria-hidden="true" tabindex="-1"></a>                                      InVec2 y,</span>
<span id="cb106-12"><a href="#cb106-12" aria-hidden="true" tabindex="-1"></a>                                      OutVec z<span class="op">)</span>;</span>
<span id="cb106-13"><a href="#cb106-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb106-14"><a href="#cb106-14" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb106-15"><a href="#cb106-15" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb106-16"><a href="#cb106-16" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb106-17"><a href="#cb106-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb106-18"><a href="#cb106-18" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb106-19"><a href="#cb106-19" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb106-20"><a href="#cb106-20" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb106-21"><a href="#cb106-21" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb106-22"><a href="#cb106-22" aria-hidden="true" tabindex="-1"></a>                                      InMat A,</span>
<span id="cb106-23"><a href="#cb106-23" aria-hidden="true" tabindex="-1"></a>                                      Triangle t,</span>
<span id="cb106-24"><a href="#cb106-24" aria-hidden="true" tabindex="-1"></a>                                      DiagonalStorage d,</span>
<span id="cb106-25"><a href="#cb106-25" aria-hidden="true" tabindex="-1"></a>                                      InVec1 x,</span>
<span id="cb106-26"><a href="#cb106-26" aria-hidden="true" tabindex="-1"></a>                                      InVec2 y,</span>
<span id="cb106-27"><a href="#cb106-27" aria-hidden="true" tabindex="-1"></a>                                      OutVec z<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>z</em></span>
such that <span class="math inline"><em>z</em> = <em>y</em> + <em>A</em><em>x</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Remarks:</em> <code>y</code> and <code>z</code> may refer to the
same vector.</p>
<h4 data-number="16.10.3.5" id="solve-a-triangular-linear-system-linalg.algs.blas2.trsv"><span class="header-section-number">16.10.3.5</span> Solve a triangular linear
system [linalg.algs.blas2.trsv]<a href="#solve-a-triangular-linear-system-linalg.algs.blas2.trsv" class="self-link"></a></h4>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xTRSV</code> and <code>xTPSV</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following requirements apply to all functions in this section.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>A.extent(1)</code> equals <code>b.extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Constraints:</em> if <code>InMat</code> has
<code>layout_blas_packed</code> layout, then the layout’s
<code>Triangle</code> template argument has the same type as the
function’s <code>Triangle</code> template argument.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> if
neither <code>A.static_extent(0)</code> nor
<code>A.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals <code>A.static_extent(1)</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> if
neither <code>A.static_extent(1)</code> nor
<code>b.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>b.static_extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Complexity:</em> All algorithms in this Clause with
<code>mdspan</code> parameters perform a count of <code>mdspan</code>
array accesses and arithmetic operations that is linear in
<code>x.extent(0)</code> times <code>A.extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Remarks:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span> The
functions will only access the triangle of <code>A</code> specified by
the <code>Triangle</code> argument <code>t</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span> If
the <code>DiagonalStorage</code> template argument has type
<code>implicit_unit_diagonal_t</code>, then the functions will not
access the diagonal of <code>A</code>, and will interpret <code>A</code>
as if each of its diagonal elements behaves as a two-sided
multiplicative identity.</p></li>
</ul>
<h5 data-number="16.10.3.5.1" id="not-in-place-triangular-solve-linalg.algs.blas2.trsv.not-in-place"><span class="header-section-number">16.10.3.5.1</span> Not-in-place triangular
solve [linalg.algs.blas2.trsv.not-in-place]<a href="#not-in-place-triangular-solve-linalg.algs.blas2.trsv.not-in-place" class="self-link"></a></h5>
<div class="sourceCode" id="cb107"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb107-1"><a href="#cb107-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb107-2"><a href="#cb107-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb107-3"><a href="#cb107-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb107-4"><a href="#cb107-4" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb107-5"><a href="#cb107-5" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec,</span>
<span id="cb107-6"><a href="#cb107-6" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb107-7"><a href="#cb107-7" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb107-8"><a href="#cb107-8" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb107-9"><a href="#cb107-9" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb107-10"><a href="#cb107-10" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb107-11"><a href="#cb107-11" aria-hidden="true" tabindex="-1"></a>  InVec b,</span>
<span id="cb107-12"><a href="#cb107-12" aria-hidden="true" tabindex="-1"></a>  OutVec x,</span>
<span id="cb107-13"><a href="#cb107-13" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb107-14"><a href="#cb107-14" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb107-15"><a href="#cb107-15" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb107-16"><a href="#cb107-16" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb107-17"><a href="#cb107-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb107-18"><a href="#cb107-18" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb107-19"><a href="#cb107-19" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec,</span>
<span id="cb107-20"><a href="#cb107-20" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb107-21"><a href="#cb107-21" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb107-22"><a href="#cb107-22" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb107-23"><a href="#cb107-23" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb107-24"><a href="#cb107-24" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb107-25"><a href="#cb107-25" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb107-26"><a href="#cb107-26" aria-hidden="true" tabindex="-1"></a>  InVec b,</span>
<span id="cb107-27"><a href="#cb107-27" aria-hidden="true" tabindex="-1"></a>  OutVec x,</span>
<span id="cb107-28"><a href="#cb107-28" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em> <code>A.extent(0)</code> equals
<code>x.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Mandates:</em> If neither <code>A.static_extent(0)</code> nor
<code>x.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>x.static_extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>x</em></span>
such that <span class="math inline"><em>b</em> = <em>A</em><em>x</em></span>. If no such
<span class="math inline"><em>x</em></span> exists, then the elements of
<span class="math inline"><em>x</em></span> are valid but
unspecified.</p>
<div class="sourceCode" id="cb108"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb108-1"><a href="#cb108-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb108-2"><a href="#cb108-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb108-3"><a href="#cb108-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb108-4"><a href="#cb108-4" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb108-5"><a href="#cb108-5" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb108-6"><a href="#cb108-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb108-7"><a href="#cb108-7" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb108-8"><a href="#cb108-8" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb108-9"><a href="#cb108-9" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb108-10"><a href="#cb108-10" aria-hidden="true" tabindex="-1"></a>  InVec b,</span>
<span id="cb108-11"><a href="#cb108-11" aria-hidden="true" tabindex="-1"></a>  OutVec x<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Equivalent to</p>
<div class="sourceCode" id="cb109"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb109-1"><a href="#cb109-1" aria-hidden="true" tabindex="-1"></a>triangular_matrix_vector_solve<span class="op">(</span>A, t, d, b, x,</span>
<span id="cb109-2"><a href="#cb109-2" aria-hidden="true" tabindex="-1"></a>  <span class="op">[](</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> A_ii, <span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> b_i<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> A_ii <span class="op">/</span> b_i; <span class="op">})</span>;</span></code></pre></div>
<div class="sourceCode" id="cb110"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb110-1"><a href="#cb110-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb110-2"><a href="#cb110-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb110-3"><a href="#cb110-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb110-4"><a href="#cb110-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb110-5"><a href="#cb110-5" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb110-6"><a href="#cb110-6" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb110-7"><a href="#cb110-7" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb110-8"><a href="#cb110-8" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb110-9"><a href="#cb110-9" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb110-10"><a href="#cb110-10" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb110-11"><a href="#cb110-11" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb110-12"><a href="#cb110-12" aria-hidden="true" tabindex="-1"></a>  InVec b,</span>
<span id="cb110-13"><a href="#cb110-13" aria-hidden="true" tabindex="-1"></a>  OutVec x<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Equivalent to</p>
<div class="sourceCode" id="cb111"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb111-1"><a href="#cb111-1" aria-hidden="true" tabindex="-1"></a>triangular_matrix_vector_solve<span class="op">(</span>forward<span class="op">&lt;</span>ExecutionPolicy<span class="op">&gt;(</span>exec<span class="op">)</span>,</span>
<span id="cb111-2"><a href="#cb111-2" aria-hidden="true" tabindex="-1"></a>  A, t, d, b, x,</span>
<span id="cb111-3"><a href="#cb111-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">[](</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> A_ii, <span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> b_i<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> A_ii <span class="op">/</span> b_i; <span class="op">})</span>;</span></code></pre></div>
<h5 data-number="16.10.3.5.2" id="in-place-triangular-solve-linalg.algs.blas2.trsv.in-place"><span class="header-section-number">16.10.3.5.2</span> In-place triangular
solve [linalg.algs.blas2.trsv.in-place]<a href="#in-place-triangular-solve-linalg.algs.blas2.trsv.in-place" class="self-link"></a></h5>
<div class="sourceCode" id="cb112"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb112-1"><a href="#cb112-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb112-2"><a href="#cb112-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb112-3"><a href="#cb112-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb112-4"><a href="#cb112-4" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec,</span>
<span id="cb112-5"><a href="#cb112-5" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb112-6"><a href="#cb112-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb112-7"><a href="#cb112-7" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb112-8"><a href="#cb112-8" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb112-9"><a href="#cb112-9" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb112-10"><a href="#cb112-10" aria-hidden="true" tabindex="-1"></a>  InOutVec b,</span>
<span id="cb112-11"><a href="#cb112-11" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb112-12"><a href="#cb112-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb112-13"><a href="#cb112-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb112-14"><a href="#cb112-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb112-15"><a href="#cb112-15" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb112-16"><a href="#cb112-16" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec,</span>
<span id="cb112-17"><a href="#cb112-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb112-18"><a href="#cb112-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb112-19"><a href="#cb112-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb112-20"><a href="#cb112-20" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb112-21"><a href="#cb112-21" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb112-22"><a href="#cb112-22" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb112-23"><a href="#cb112-23" aria-hidden="true" tabindex="-1"></a>  InOutVec b,</span>
<span id="cb112-24"><a href="#cb112-24" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> Performing triangular solve in place hinders
parallelization. However, other <code>ExecutionPolicy</code>-specific
optimizations, such as vectorization, are still possible. This is why
the <code>ExecutionPolicy</code> overload exists. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em> <code>A.extent(0)</code> equals
<code>b.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Mandates:</em> If neither <code>A.static_extent(0)</code> nor
<code>b.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>b.static_extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Effects:</em> Overwrites <span class="math inline"><em>b</em></span>
with <span class="math inline"><em>x</em></span> such that <span class="math inline"><em>b</em> = <em>A</em><em>x</em></span>. If no such
<span class="math inline"><em>x</em></span> exists, then the elements of
<span class="math inline"><em>b</em></span> are valid but
unspecified.</p>
<div class="sourceCode" id="cb113"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb113-1"><a href="#cb113-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb113-2"><a href="#cb113-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb113-3"><a href="#cb113-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb113-4"><a href="#cb113-4" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec<span class="op">&gt;</span></span>
<span id="cb113-5"><a href="#cb113-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb113-6"><a href="#cb113-6" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb113-7"><a href="#cb113-7" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb113-8"><a href="#cb113-8" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb113-9"><a href="#cb113-9" aria-hidden="true" tabindex="-1"></a>  InOutVec b<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Equivalent to</p>
<div class="sourceCode" id="cb114"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb114-1"><a href="#cb114-1" aria-hidden="true" tabindex="-1"></a>triangular_matrix_vector_solve<span class="op">(</span>A, t, d, b,</span>
<span id="cb114-2"><a href="#cb114-2" aria-hidden="true" tabindex="-1"></a>  <span class="op">[](</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> A_ii, <span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> b_i<span class="op">){</span> <span class="cf">return</span> A_ii <span class="op">/</span> b_i; <span class="op">})</span>;</span></code></pre></div>
<div class="sourceCode" id="cb115"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb115-1"><a href="#cb115-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb115-2"><a href="#cb115-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb115-3"><a href="#cb115-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb115-4"><a href="#cb115-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb115-5"><a href="#cb115-5" aria-hidden="true" tabindex="-1"></a>         <em>inout-vector</em> InOutVec<span class="op">&gt;</span></span>
<span id="cb115-6"><a href="#cb115-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_vector_solve<span class="op">(</span></span>
<span id="cb115-7"><a href="#cb115-7" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb115-8"><a href="#cb115-8" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb115-9"><a href="#cb115-9" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb115-10"><a href="#cb115-10" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb115-11"><a href="#cb115-11" aria-hidden="true" tabindex="-1"></a>  InOutVec b<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Equivalent to</p>
<div class="sourceCode" id="cb116"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb116-1"><a href="#cb116-1" aria-hidden="true" tabindex="-1"></a>triangular_matrix_vector_solve<span class="op">(</span>forward<span class="op">&lt;</span>ExecutionPolicy<span class="op">&gt;(</span>exec<span class="op">)</span>,</span>
<span id="cb116-2"><a href="#cb116-2" aria-hidden="true" tabindex="-1"></a>  A, t, d, b,</span>
<span id="cb116-3"><a href="#cb116-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">[](</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> A_ii, <span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> b_i<span class="op">){</span> <span class="cf">return</span> A_ii <span class="op">/</span> b_i; <span class="op">})</span>;</span></code></pre></div>
<h4 data-number="16.10.3.6" id="rank-1-outer-product-update-of-a-matrix-linalg.algs.blas2.rank1"><span class="header-section-number">16.10.3.6</span> Rank-1 (outer product)
update of a matrix [linalg.algs.blas2.rank1]<a href="#rank-1-outer-product-update-of-a-matrix-linalg.algs.blas2.rank1" class="self-link"></a></h4>
<h5 data-number="16.10.3.6.1" id="nonsymmetric-nonconjugated-rank-1-update-linalg.algs.blas2.rank1.geru"><span class="header-section-number">16.10.3.6.1</span> Nonsymmetric
nonconjugated rank-1 update [linalg.algs.blas2.rank1.geru]<a href="#nonsymmetric-nonconjugated-rank-1-update-linalg.algs.blas2.rank1.geru" class="self-link"></a></h5>
<div class="sourceCode" id="cb117"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb117-1"><a href="#cb117-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb117-2"><a href="#cb117-2" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb117-3"><a href="#cb117-3" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb117-4"><a href="#cb117-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_rank_1_update<span class="op">(</span></span>
<span id="cb117-5"><a href="#cb117-5" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb117-6"><a href="#cb117-6" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb117-7"><a href="#cb117-7" aria-hidden="true" tabindex="-1"></a>  InOutMat A<span class="op">)</span>;</span>
<span id="cb117-8"><a href="#cb117-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb117-9"><a href="#cb117-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb117-10"><a href="#cb117-10" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb117-11"><a href="#cb117-11" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb117-12"><a href="#cb117-12" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb117-13"><a href="#cb117-13" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_rank_1_update<span class="op">(</span></span>
<span id="cb117-14"><a href="#cb117-14" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb117-15"><a href="#cb117-15" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb117-16"><a href="#cb117-16" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb117-17"><a href="#cb117-17" aria-hidden="true" tabindex="-1"></a>  InOutMat A<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> This function corresponds to the BLAS functions
<code>xGER</code> (for real element types) and <code>xGERU</code> (for
complex element types). <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>A.extent(0)</code> equals <code>x.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>A.extent(1)</code> equals <code>y.extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>x.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>x.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span> If
neither <code>A.static_extent(1)</code> nor
<code>y.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>y.static_extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Effects:</em> Overwrites <span class="math inline"><em>A</em></span>
with <span class="math inline"><em>A</em>′</span> such that <span class="math inline"><em>A</em>′ = <em>x</em><em>y</em><sup><em>T</em></sup></span>,
where <span class="math inline"><em>y</em><sup><em>T</em></sup></span>
denotes the transpose of the column vector <span class="math inline"><em>y</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>x.extent(0)</code> times
<code>y.extent(0)</code>.</p>
<p><i>[Note:</i> Users can get <code>xGERC</code> behavior by giving the
second argument as the result of <code>conjugated</code>. Alternately,
they can use the shortcut <code>matrix_rank_1_update_c</code> below.
<i>– end note]</i></p>
<h5 data-number="16.10.3.6.2" id="nonsymmetric-conjugated-rank-1-update-linalg.algs.blas2.rank1.gerc"><span class="header-section-number">16.10.3.6.2</span> Nonsymmetric conjugated
rank-1 update [linalg.algs.blas2.rank1.gerc]<a href="#nonsymmetric-conjugated-rank-1-update-linalg.algs.blas2.rank1.gerc" class="self-link"></a></h5>
<div class="sourceCode" id="cb118"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb118-1"><a href="#cb118-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb118-2"><a href="#cb118-2" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb118-3"><a href="#cb118-3" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb118-4"><a href="#cb118-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_rank_1_update_c<span class="op">(</span></span>
<span id="cb118-5"><a href="#cb118-5" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb118-6"><a href="#cb118-6" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb118-7"><a href="#cb118-7" aria-hidden="true" tabindex="-1"></a>  InOutMat A<span class="op">)</span>;</span>
<span id="cb118-8"><a href="#cb118-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb118-9"><a href="#cb118-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb118-10"><a href="#cb118-10" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb118-11"><a href="#cb118-11" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb118-12"><a href="#cb118-12" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb118-13"><a href="#cb118-13" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_rank_1_update_c<span class="op">(</span></span>
<span id="cb118-14"><a href="#cb118-14" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb118-15"><a href="#cb118-15" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb118-16"><a href="#cb118-16" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb118-17"><a href="#cb118-17" aria-hidden="true" tabindex="-1"></a>  InOutMat A<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> This function corresponds to the BLAS functions
<code>xGER</code> (for real element types) and <code>xGERC</code> (for
complex element types). <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Equivalent to
<code>matrix_rank_1_update(x, conjugated(y), A);</code>.</p>
<h5 data-number="16.10.3.6.3" id="rank-1-update-of-a-symmetric-matrix-linalg.algs.blas2.rank1.syr"><span class="header-section-number">16.10.3.6.3</span> Rank-1 update of a
Symmetric matrix [linalg.algs.blas2.rank1.syr]<a href="#rank-1-update-of-a-symmetric-matrix-linalg.algs.blas2.rank1.syr" class="self-link"></a></h5>
<div class="sourceCode" id="cb119"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb119-1"><a href="#cb119-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec,</span>
<span id="cb119-2"><a href="#cb119-2" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb119-3"><a href="#cb119-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb119-4"><a href="#cb119-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb119-5"><a href="#cb119-5" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb119-6"><a href="#cb119-6" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb119-7"><a href="#cb119-7" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb119-8"><a href="#cb119-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb119-9"><a href="#cb119-9" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb119-10"><a href="#cb119-10" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb119-11"><a href="#cb119-11" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb119-12"><a href="#cb119-12" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb119-13"><a href="#cb119-13" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb119-14"><a href="#cb119-14" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb119-15"><a href="#cb119-15" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb119-16"><a href="#cb119-16" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb119-17"><a href="#cb119-17" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T,</span>
<span id="cb119-18"><a href="#cb119-18" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb119-19"><a href="#cb119-19" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb119-20"><a href="#cb119-20" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb119-21"><a href="#cb119-21" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb119-22"><a href="#cb119-22" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb119-23"><a href="#cb119-23" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb119-24"><a href="#cb119-24" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb119-25"><a href="#cb119-25" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb119-26"><a href="#cb119-26" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb119-27"><a href="#cb119-27" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T,</span>
<span id="cb119-28"><a href="#cb119-28" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb119-29"><a href="#cb119-29" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb119-30"><a href="#cb119-30" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb119-31"><a href="#cb119-31" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb119-32"><a href="#cb119-32" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb119-33"><a href="#cb119-33" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb119-34"><a href="#cb119-34" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb119-35"><a href="#cb119-35" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb119-36"><a href="#cb119-36" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xSYR</code> and <code>xSPR</code>.</p>
<p>They have overloads taking a scaling factor <code>alpha</code>,
because it would be impossible to express updates like <span class="math inline"><em>C</em> = <em>C</em> − <em>x</em><em>x</em><sup><em>T</em></sup></span>
otherwise. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>A.extent(0)</code> equals <code>x.extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> If <code>A</code> has
<code>layout_blas_packed</code> layout, then the layout’s
<code>Triangle</code> template argument has the same type as the
function’s <code>Triangle</code> template argument.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>A.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>A.static_extent(1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>x.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>x.static_extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
Overloads without an <code>alpha</code> parameter overwrite <span class="math inline"><em>A</em></span> with <span class="math inline"><em>A</em>′</span> such that <span class="math inline"><em>A</em>′ = <em>A</em> + <em>x</em><em>x</em><sup><em>T</em></sup></span>,
where <span class="math inline"><em>x</em><sup><em>T</em></sup></span>
denotes the transpose of the column vector <span class="math inline"><em>x</em></span>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
Overloads with an <code>alpha</code> parameter overwrite <span class="math inline"><em>A</em></span> with <span class="math inline"><em>A</em>′</span> such that <span class="math inline"><em>A</em>′ = <em>A</em> + <em>α</em><em>x</em><em>x</em><sup><em>T</em></sup></span>,
where the scalar <span class="math inline"><em>α</em></span> is
<code>alpha</code> and <span class="math inline"><em>x</em><sup><em>T</em></sup></span> denotes the
transpose of the column vector <span class="math inline"><em>x</em></span>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>x.extent(0)</code> times
<code>x.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Remarks:</em> The functions will only access the triangle of
<code>A</code> specified by the <code>Triangle</code> argument
<code>t</code>, and will interpret the value <code>A[i,j]</code> as
equal to <code>A[j,i]</code> for indices <code>i,j</code> in the domain
<code>A</code> but outside that triangle.</p>
<h5 data-number="16.10.3.6.4" id="rank-1-update-of-a-hermitian-matrix-linalg.algs.blas2.rank1.her"><span class="header-section-number">16.10.3.6.4</span> Rank-1 update of a
Hermitian matrix [linalg.algs.blas2.rank1.her]<a href="#rank-1-update-of-a-hermitian-matrix-linalg.algs.blas2.rank1.her" class="self-link"></a></h5>
<div class="sourceCode" id="cb120"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb120-1"><a href="#cb120-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec,</span>
<span id="cb120-2"><a href="#cb120-2" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb120-3"><a href="#cb120-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb120-4"><a href="#cb120-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb120-5"><a href="#cb120-5" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb120-6"><a href="#cb120-6" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb120-7"><a href="#cb120-7" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb120-8"><a href="#cb120-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb120-9"><a href="#cb120-9" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb120-10"><a href="#cb120-10" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb120-11"><a href="#cb120-11" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb120-12"><a href="#cb120-12" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb120-13"><a href="#cb120-13" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb120-14"><a href="#cb120-14" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb120-15"><a href="#cb120-15" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb120-16"><a href="#cb120-16" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb120-17"><a href="#cb120-17" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T,</span>
<span id="cb120-18"><a href="#cb120-18" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb120-19"><a href="#cb120-19" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb120-20"><a href="#cb120-20" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb120-21"><a href="#cb120-21" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb120-22"><a href="#cb120-22" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb120-23"><a href="#cb120-23" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb120-24"><a href="#cb120-24" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb120-25"><a href="#cb120-25" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb120-26"><a href="#cb120-26" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb120-27"><a href="#cb120-27" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T,</span>
<span id="cb120-28"><a href="#cb120-28" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb120-29"><a href="#cb120-29" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb120-30"><a href="#cb120-30" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb120-31"><a href="#cb120-31" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span></span>
<span id="cb120-32"><a href="#cb120-32" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb120-33"><a href="#cb120-33" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb120-34"><a href="#cb120-34" aria-hidden="true" tabindex="-1"></a>  InVec x,</span>
<span id="cb120-35"><a href="#cb120-35" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb120-36"><a href="#cb120-36" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xHER</code> and <code>xHPR</code>.</p>
<p>They have overloads taking a scaling factor <code>alpha</code>,
because it would be impossible to express the update <span class="math inline"><em>A</em> = <em>A</em> − <em>x</em><em>x</em><sup><em>H</em></sup></span>
otherwise. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>; and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>A.extent(0)</code> equals <code>x.extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> If <code>A</code> has
<code>layout_blas_packed</code> layout, then the layout’s
<code>Triangle</code> template argument has the same type as the
function’s <code>Triangle</code> template argument.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>A.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>A.static_extent(1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>x.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>x.static_extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
Overloads without an <code>alpha</code> parameter overwrite <span class="math inline"><em>A</em></span> with <span class="math inline"><em>A</em>′</span> such that <span class="math inline"><em>A</em>′ = <em>A</em> + <em>x</em><em>x</em><sup><em>H</em></sup></span>,
where <span class="math inline"><em>x</em><sup><em>H</em></sup></span>
denotes the conjugate transpose of the column vector <span class="math inline"><em>x</em></span>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
Overloads with an <code>alpha</code> parameter overwrite <span class="math inline"><em>A</em></span> with <span class="math inline"><em>A</em>′</span> such that <span class="math inline"><em>A</em>′ = <em>A</em> + <em>α</em><em>x</em><em>x</em><sup><em>H</em></sup></span>,
where the scalar <span class="math inline"><em>α</em></span> is
<code>alpha</code> and <span class="math inline"><em>x</em><sup><em>H</em></sup></span> denotes the
conjugate transpose of the column vector <span class="math inline"><em>x</em></span>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>x.extent(0)</code> times
<code>x.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Remarks:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span> The
functions will only access the triangle of <code>A</code> specified by
the <code>Triangle</code> argument <code>t</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span> For
indices <code>i,j</code> in the domain of <code>A</code> but outside the
triangle specified by <code>t</code>, the functions will interpret the
value <code>A[i,j]</code> as equal to
<em><code>conj-if-needed</code></em><code>(A[j,i])</code>.</p></li>
</ul>
<h4 data-number="16.10.3.7" id="rank-2-update-of-a-symmetric-matrix-linalg.algs.blas2.rank2.syr2"><span class="header-section-number">16.10.3.7</span> Rank-2 update of a
symmetric matrix [linalg.algs.blas2.rank2.syr2]<a href="#rank-2-update-of-a-symmetric-matrix-linalg.algs.blas2.rank2.syr2" class="self-link"></a></h4>
<div class="sourceCode" id="cb121"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb121-1"><a href="#cb121-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb121-2"><a href="#cb121-2" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb121-3"><a href="#cb121-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb121-4"><a href="#cb121-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb121-5"><a href="#cb121-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_2_update<span class="op">(</span></span>
<span id="cb121-6"><a href="#cb121-6" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb121-7"><a href="#cb121-7" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb121-8"><a href="#cb121-8" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb121-9"><a href="#cb121-9" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb121-10"><a href="#cb121-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb121-11"><a href="#cb121-11" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb121-12"><a href="#cb121-12" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb121-13"><a href="#cb121-13" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb121-14"><a href="#cb121-14" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb121-15"><a href="#cb121-15" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb121-16"><a href="#cb121-16" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_2_update<span class="op">(</span></span>
<span id="cb121-17"><a href="#cb121-17" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb121-18"><a href="#cb121-18" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb121-19"><a href="#cb121-19" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb121-20"><a href="#cb121-20" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb121-21"><a href="#cb121-21" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xSYR2</code> and <code>xSPR2</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>A.extent(0)</code> equals <code>x.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
<code>A.extent(0)</code> equals <code>y.extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> If <code>A</code> has
<code>layout_blas_packed</code> layout, then the layout’s
<code>Triangle</code> template argument has the same type as the
function’s <code>Triangle</code> template argument.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>A.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>A.static_extent(1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>x.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>x.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span> If
neither <code>A.static_extent(0)</code> or
<code>y.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>y.static_extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em> Overwrites <span class="math inline"><em>A</em></span>
with <span class="math inline"><em>A</em>′</span> such that <span class="math inline"><em>A</em>′ = <em>A</em> + <em>x</em><em>y</em><sup><em>T</em></sup> + <em>y</em><em>x</em><sup><em>T</em></sup></span>,
where <span class="math inline"><em>x</em><sup><em>T</em></sup></span>
denotes the transpose of the column vector <span class="math inline"><em>x</em></span>, and <span class="math inline"><em>y</em><sup><em>T</em></sup></span> denotes the
transpose of the column vector <span class="math inline"><em>y</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>x.extent(0)</code> times
<code>y.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Remarks:</em> The functions will only access the triangle of
<code>A</code> specified by the <code>Triangle</code> argument
<code>t</code>, and will interpret the value <code>A[i,j]</code> as
equal to <code>A[j,i]</code> for indices <code>i,j</code> in the domain
<code>A</code> but outside that triangle.</p>
<h4 data-number="16.10.3.8" id="rank-2-update-of-a-hermitian-matrix-linalg.algs.blas2.rank2.her2"><span class="header-section-number">16.10.3.8</span> Rank-2 update of a
Hermitian matrix [linalg.algs.blas2.rank2.her2]<a href="#rank-2-update-of-a-hermitian-matrix-linalg.algs.blas2.rank2.her2" class="self-link"></a></h4>
<div class="sourceCode" id="cb122"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb122-1"><a href="#cb122-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1,</span>
<span id="cb122-2"><a href="#cb122-2" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb122-3"><a href="#cb122-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb122-4"><a href="#cb122-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb122-5"><a href="#cb122-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_2_update<span class="op">(</span></span>
<span id="cb122-6"><a href="#cb122-6" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb122-7"><a href="#cb122-7" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb122-8"><a href="#cb122-8" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb122-9"><a href="#cb122-9" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb122-10"><a href="#cb122-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb122-11"><a href="#cb122-11" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb122-12"><a href="#cb122-12" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec1,</span>
<span id="cb122-13"><a href="#cb122-13" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec2,</span>
<span id="cb122-14"><a href="#cb122-14" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb122-15"><a href="#cb122-15" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb122-16"><a href="#cb122-16" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_2_update<span class="op">(</span></span>
<span id="cb122-17"><a href="#cb122-17" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb122-18"><a href="#cb122-18" aria-hidden="true" tabindex="-1"></a>  InVec1 x,</span>
<span id="cb122-19"><a href="#cb122-19" aria-hidden="true" tabindex="-1"></a>  InVec2 y,</span>
<span id="cb122-20"><a href="#cb122-20" aria-hidden="true" tabindex="-1"></a>  InOutMat A,</span>
<span id="cb122-21"><a href="#cb122-21" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xHER2</code> and <code>xHPR2</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>A.extent(0)</code> equals <code>x.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
<code>A.extent(0)</code> equals <code>y.extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> If <code>A</code> has
<code>layout_blas_packed</code> layout, then the layout’s
<code>Triangle</code> template argument has the same type as the
function’s <code>Triangle</code> template argument.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>A.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>A.static_extent(1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>x.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>x.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>y.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>y.static_extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em> Overwrites <span class="math inline"><em>A</em></span>
with <span class="math inline"><em>A</em>′</span> such that <span class="math inline"><em>A</em>′ = <em>A</em> + <em>x</em><em>y</em><sup><em>H</em></sup> + <em>y</em><em>x</em><sup><em>H</em></sup></span>,
where <span class="math inline"><em>x</em><sup><em>H</em></sup></span>
denotes the conjugate transpose of the column vector <span class="math inline"><em>x</em></span>, and <span class="math inline"><em>y</em><sup><em>H</em></sup></span> denotes the
conjugate transpose of the column vector <span class="math inline"><em>y</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>x.extent(0)</code> times
<code>y.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Remarks:</em> The functions will only access the triangle of
<code>A</code> specified by the <code>Triangle</code> argument
<code>t</code>, and will interpret the value <code>A[i,j]</code> as
equal to <em><code>conj-if-needed</code></em><code>(A[j,i])</code> for
indices <code>i,j</code> in the domain of <code>A</code> but outside the
triangle specified by <code>t</code>.</p>
<h3 data-number="16.10.4" id="blas-3-functions-linalg.algs.blas3"><span class="header-section-number">16.10.4</span> BLAS 3 functions
[linalg.algs.blas3]<a href="#blas-3-functions-linalg.algs.blas3" class="self-link"></a></h3>
<h4 data-number="16.10.4.1" id="general-matrix-matrix-product-linalg.algs.blas3.gemm"><span class="header-section-number">16.10.4.1</span> General matrix-matrix
product [linalg.algs.blas3.gemm]<a href="#general-matrix-matrix-product-linalg.algs.blas3.gemm" class="self-link"></a></h4>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xGEMM</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following requirements apply to all functions in this section.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>C.extent(0)</code> equals <code>E.extent(0)</code> (if
applicable),</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>C.extent(1)</code> equals <code>E.extent(1)</code> (if
applicable),</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<code>A.extent(1)</code> equals <code>B.extent(0)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.4)</a></span>
<code>A.extent(0)</code> equals <code>C.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.5)</a></span>
<code>B.extent(1)</code> equals <code>C.extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> For
all <code>r</code> in 0, 1, …, <code>C.rank()</code> - 1, if neither
<code>C.static_extent(r)</code> nor <code>E.static_extent(r)</code>
equals <code>dynamic_extent</code>, then <code>C.static_extent(r)</code>
equals <code>E.static_extent(r)</code> (if applicable).</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> If
neither <code>A.static_extent(1)</code> nor
<code>B.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>B.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>C.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>C.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.4)</a></span> If
neither <code>B.static_extent(1)</code> nor
<code>C.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>B.static_extent(1)</code> equals
<code>C.static_extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Complexity:</em> For all algorithms in this Clause, the count of
<code>mdspan</code> array accesses and arithmetic operations is linear
in <code>A.extent(0)</code> times <code>B.extent(1)</code> times
<code>A.extent(1)</code>.</p>
<h5 data-number="16.10.4.1.1" id="overwriting-general-matrix-matrix-product"><span class="header-section-number">16.10.4.1.1</span> Overwriting general
matrix-matrix product<a href="#overwriting-general-matrix-matrix-product" class="self-link"></a></h5>
<div class="sourceCode" id="cb123"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb123-1"><a href="#cb123-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb123-2"><a href="#cb123-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb123-3"><a href="#cb123-3" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb123-4"><a href="#cb123-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_product<span class="op">(</span>InMat1 A,</span>
<span id="cb123-5"><a href="#cb123-5" aria-hidden="true" tabindex="-1"></a>                    InMat2 B,</span>
<span id="cb123-6"><a href="#cb123-6" aria-hidden="true" tabindex="-1"></a>                    OutMat C<span class="op">)</span>;</span>
<span id="cb123-7"><a href="#cb123-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb123-8"><a href="#cb123-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb123-9"><a href="#cb123-9" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb123-10"><a href="#cb123-10" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb123-11"><a href="#cb123-11" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb123-12"><a href="#cb123-12" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb123-13"><a href="#cb123-13" aria-hidden="true" tabindex="-1"></a>                    InMat1 A,</span>
<span id="cb123-14"><a href="#cb123-14" aria-hidden="true" tabindex="-1"></a>                    InMat2 B,</span>
<span id="cb123-15"><a href="#cb123-15" aria-hidden="true" tabindex="-1"></a>                    OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>A</em><em>B</em></span>.</p>
<h5 data-number="16.10.4.1.2" id="updating-general-matrix-matrix-product"><span class="header-section-number">16.10.4.1.2</span> Updating general
matrix-matrix product<a href="#updating-general-matrix-matrix-product" class="self-link"></a></h5>
<div class="sourceCode" id="cb124"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb124-1"><a href="#cb124-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb124-2"><a href="#cb124-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb124-3"><a href="#cb124-3" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb124-4"><a href="#cb124-4" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb124-5"><a href="#cb124-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_product<span class="op">(</span>InMat1 A,</span>
<span id="cb124-6"><a href="#cb124-6" aria-hidden="true" tabindex="-1"></a>                    InMat2 B,</span>
<span id="cb124-7"><a href="#cb124-7" aria-hidden="true" tabindex="-1"></a>                    InMat3 E,</span>
<span id="cb124-8"><a href="#cb124-8" aria-hidden="true" tabindex="-1"></a>                    OutMat C<span class="op">)</span>;</span>
<span id="cb124-9"><a href="#cb124-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb124-10"><a href="#cb124-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb124-11"><a href="#cb124-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb124-12"><a href="#cb124-12" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb124-13"><a href="#cb124-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb124-14"><a href="#cb124-14" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb124-15"><a href="#cb124-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> matrix_product<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb124-16"><a href="#cb124-16" aria-hidden="true" tabindex="-1"></a>                    InMat1 A,</span>
<span id="cb124-17"><a href="#cb124-17" aria-hidden="true" tabindex="-1"></a>                    InMat2 B,</span>
<span id="cb124-18"><a href="#cb124-18" aria-hidden="true" tabindex="-1"></a>                    InMat3 E,</span>
<span id="cb124-19"><a href="#cb124-19" aria-hidden="true" tabindex="-1"></a>                    OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>E</em> + <em>A</em><em>B</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Remarks:</em> <code>C</code> and <code>E</code> may refer to the
same matrix.</p>
<h4 data-number="16.10.4.2" id="symmetric-matrix-matrix-product-linalg.algs.blas3.symm"><span class="header-section-number">16.10.4.2</span> Symmetric matrix-matrix
product [linalg.algs.blas3.symm]<a href="#symmetric-matrix-matrix-product-linalg.algs.blas3.symm" class="self-link"></a></h4>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xSYMM</code>.</p>
<p>Unlike the symmetric rank-1 or rank-k update functions, these
functions assume that the input matrix <code>A</code> – not the output
matrix – is symmetric. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following requirements apply to all functions in this section.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>C.extent(0)</code> equals <code>E.extent(0)</code> (if
applicable), and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<code>C.extent(1)</code> equals <code>E.extent(1)</code> (if
applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Constraints:</em> If <code>InMat1</code> has
<code>layout_blas_packed</code> layout, then the layout’s
<code>Triangle</code> template argument has the same type as the
function’s <code>Triangle</code> template argument.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>A.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>A.static_extent(1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> For
all <code>r</code> in 0, 1, …, <code>C.rank()</code> - 1, if neither
<code>C.static_extent(r)</code> nor <code>E.static_extent(r)</code>
equals <code>dynamic_extent</code>, then <code>C.static_extent(r)</code>
equals <code>E.static_extent(r)</code> (if applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Remarks:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span> The
functions will only access the triangle of <code>A</code> specified by
the <code>Triangle</code> argument <code>t</code>, and will interpret
the value <code>A[i,j]</code> as equal to <code>A[j,i]</code> for
indices <code>i,j</code> in the domain <code>A</code> but outside that
triangle.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
<code>C</code> and <code>E</code> (if applicable) may refer to the same
matrix.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
The following requirements apply to all overloads of
<code>symmetric_matrix_left_product</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.1)</a></span>
<code>A.extent(1)</code> equals <code>B.extent(0)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.2)</a></span>
<code>A.extent(0)</code> equals <code>C.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.3)</a></span>
<code>B.extent(1)</code> equals <code>C.extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(8.1)</a></span> if
neither <code>A.static_extent(1)</code> nor
<code>B.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>B.static_extent(0)</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(8.2)</a></span> if
neither <code>A.static_extent(0)</code> nor
<code>C.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals <code>C.static_extent(0)</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(8.3)</a></span> if
neither <code>B.static_extent(1)</code> nor
<code>C.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>B.static_extent(1)</code> equals
<code>C.static_extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>A.extent(0)</code> times
<code>B.extent(1)</code> times <code>A.extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span> The
following requirements apply to all overloads of
<code>symmetric_matrix_right_product</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.1)</a></span>
<code>B.extent(1)</code> equals <code>A.extent(0)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.2)</a></span>
<code>B.extent(0)</code> equals <code>C.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.3)</a></span>
<code>A.extent(1)</code> equals <code>C.extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.1)</a></span> if
neither <code>B.static_extent(1)</code> nor
<code>A.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>B.static_extent(1)</code> equals
<code>A.static_extent(0)</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.2)</a></span> if
neither <code>B.static_extent(0)</code> nor
<code>C.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>B.static_extent(0)</code> equals <code>C.static_extent(0)</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.3)</a></span> if
neither <code>A.static_extent(1)</code> nor
<code>C.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>C.static_extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">13</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>B.extent(0)</code> times
<code>A.extent(1)</code> times <code>B.extent(1)</code>.</p>
<h5 data-number="16.10.4.2.1" id="overwriting-symmetric-matrix-matrix-left-product-linalg.algs.blas3.symm.ov.left"><span class="header-section-number">16.10.4.2.1</span> Overwriting symmetric
matrix-matrix left product [linalg.algs.blas3.symm.ov.left]<a href="#overwriting-symmetric-matrix-matrix-left-product-linalg.algs.blas3.symm.ov.left" class="self-link"></a></h5>
<div class="sourceCode" id="cb125"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb125-1"><a href="#cb125-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb125-2"><a href="#cb125-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb125-3"><a href="#cb125-3" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb125-4"><a href="#cb125-4" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb125-5"><a href="#cb125-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_left_product<span class="op">(</span></span>
<span id="cb125-6"><a href="#cb125-6" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb125-7"><a href="#cb125-7" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb125-8"><a href="#cb125-8" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb125-9"><a href="#cb125-9" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb125-10"><a href="#cb125-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb125-11"><a href="#cb125-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb125-12"><a href="#cb125-12" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb125-13"><a href="#cb125-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb125-14"><a href="#cb125-14" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb125-15"><a href="#cb125-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_left_product<span class="op">(</span></span>
<span id="cb125-16"><a href="#cb125-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb125-17"><a href="#cb125-17" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb125-18"><a href="#cb125-18" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb125-19"><a href="#cb125-19" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb125-20"><a href="#cb125-20" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>A</em><em>B</em></span>.</p>
<h5 data-number="16.10.4.2.2" id="overwriting-symmetric-matrix-matrix-right-product-linalg.algs.blas3.symm.ov.right"><span class="header-section-number">16.10.4.2.2</span> Overwriting symmetric
matrix-matrix right product [linalg.algs.blas3.symm.ov.right]<a href="#overwriting-symmetric-matrix-matrix-right-product-linalg.algs.blas3.symm.ov.right" class="self-link"></a></h5>
<div class="sourceCode" id="cb126"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb126-1"><a href="#cb126-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb126-2"><a href="#cb126-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb126-3"><a href="#cb126-3" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb126-4"><a href="#cb126-4" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb126-5"><a href="#cb126-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_right_product<span class="op">(</span></span>
<span id="cb126-6"><a href="#cb126-6" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb126-7"><a href="#cb126-7" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb126-8"><a href="#cb126-8" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb126-9"><a href="#cb126-9" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb126-10"><a href="#cb126-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb126-11"><a href="#cb126-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb126-12"><a href="#cb126-12" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb126-13"><a href="#cb126-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb126-14"><a href="#cb126-14" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb126-15"><a href="#cb126-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_right_product<span class="op">(</span></span>
<span id="cb126-16"><a href="#cb126-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb126-17"><a href="#cb126-17" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb126-18"><a href="#cb126-18" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb126-19"><a href="#cb126-19" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb126-20"><a href="#cb126-20" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>B</em><em>A</em></span>.</p>
<h5 data-number="16.10.4.2.3" id="updating-symmetric-matrix-matrix-left-product-linalg.algs.blas3.symm.up.left"><span class="header-section-number">16.10.4.2.3</span> Updating symmetric
matrix-matrix left product [linalg.algs.blas3.symm.up.left]<a href="#updating-symmetric-matrix-matrix-left-product-linalg.algs.blas3.symm.up.left" class="self-link"></a></h5>
<div class="sourceCode" id="cb127"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb127-1"><a href="#cb127-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb127-2"><a href="#cb127-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb127-3"><a href="#cb127-3" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb127-4"><a href="#cb127-4" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb127-5"><a href="#cb127-5" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb127-6"><a href="#cb127-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_left_product<span class="op">(</span></span>
<span id="cb127-7"><a href="#cb127-7" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb127-8"><a href="#cb127-8" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb127-9"><a href="#cb127-9" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb127-10"><a href="#cb127-10" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb127-11"><a href="#cb127-11" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb127-12"><a href="#cb127-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb127-13"><a href="#cb127-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb127-14"><a href="#cb127-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb127-15"><a href="#cb127-15" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb127-16"><a href="#cb127-16" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb127-17"><a href="#cb127-17" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb127-18"><a href="#cb127-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_left_product<span class="op">(</span></span>
<span id="cb127-19"><a href="#cb127-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb127-20"><a href="#cb127-20" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb127-21"><a href="#cb127-21" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb127-22"><a href="#cb127-22" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb127-23"><a href="#cb127-23" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb127-24"><a href="#cb127-24" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>E</em> + <em>A</em><em>B</em></span>.</p>
<h5 data-number="16.10.4.2.4" id="updating-symmetric-matrix-matrix-right-product-linalg.algs.blas3.symm.up.right"><span class="header-section-number">16.10.4.2.4</span> Updating symmetric
matrix-matrix right product [linalg.algs.blas3.symm.up.right]<a href="#updating-symmetric-matrix-matrix-right-product-linalg.algs.blas3.symm.up.right" class="self-link"></a></h5>
<div class="sourceCode" id="cb128"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb128-1"><a href="#cb128-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb128-2"><a href="#cb128-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb128-3"><a href="#cb128-3" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb128-4"><a href="#cb128-4" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb128-5"><a href="#cb128-5" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb128-6"><a href="#cb128-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_right_product<span class="op">(</span></span>
<span id="cb128-7"><a href="#cb128-7" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb128-8"><a href="#cb128-8" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb128-9"><a href="#cb128-9" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb128-10"><a href="#cb128-10" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb128-11"><a href="#cb128-11" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb128-12"><a href="#cb128-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb128-13"><a href="#cb128-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb128-14"><a href="#cb128-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb128-15"><a href="#cb128-15" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb128-16"><a href="#cb128-16" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb128-17"><a href="#cb128-17" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb128-18"><a href="#cb128-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_right_product<span class="op">(</span></span>
<span id="cb128-19"><a href="#cb128-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb128-20"><a href="#cb128-20" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb128-21"><a href="#cb128-21" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb128-22"><a href="#cb128-22" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb128-23"><a href="#cb128-23" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb128-24"><a href="#cb128-24" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>E</em> + <em>B</em><em>A</em></span>.</p>
<h4 data-number="16.10.4.3" id="hermitian-matrix-matrix-product-linalg.algs.blas3.hemm"><span class="header-section-number">16.10.4.3</span> Hermitian matrix-matrix
product [linalg.algs.blas3.hemm]<a href="#hermitian-matrix-matrix-product-linalg.algs.blas3.hemm" class="self-link"></a></h4>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xHEMM</code>.</p>
<p>Unlike the Hermitian rank-1 or rank-k update functions, these
functions assume that the input matrix – not the output matrix – is
Hermitian. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following requirements apply to all functions in this section.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>C.extent(0)</code> equals <code>E.extent(0)</code> (if
applicable), and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<code>C.extent(1)</code> equals <code>E.extent(1)</code> (if
applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Constraints:</em> If <code>InMat1</code> has
<code>layout_blas_packed</code> layout, then the layout’s
<code>Triangle</code> template argument has the same type as the
function’s <code>Triangle</code> template argument.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>A.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>A.static_extent(1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> For
all <code>r</code> in 0, 1, …, <code>C.rank()</code> - 1, if neither
<code>C.static_extent(r)</code> nor <code>E.static_extent(r)</code>
equals <code>dynamic_extent</code>, then <code>C.static_extent(r)</code>
equals <code>E.static_extent(r)</code> (if applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Remarks:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span> The
functions will only access the triangle of <code>A</code> specified by
the <code>Triangle</code> argument <code>t</code>, and will interpret
the value <code>A[i,j]</code> as equal to
<em><code>conj-if-needed</code></em><code>(A[j,i])</code> for indices
<code>i,j</code> in the domain of <code>A</code> but outside the
triangle specified by <code>t</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span>
<code>C</code> and <code>E</code> (if applicable) may refer to the same
matrix.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
The following requirements apply to all overloads of
<code>hermitian_matrix_left_product</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.1)</a></span>
<code>A.extent(1)</code> equals <code>B.extent(0)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.2)</a></span>
<code>A.extent(0)</code> equals <code>C.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.3)</a></span>
<code>B.extent(1)</code> equals <code>C.extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(8.1)</a></span> If
neither <code>A.static_extent(1)</code> nor
<code>B.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>B.static_extent(0)</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(8.2)</a></span> if
neither <code>A.static_extent(0)</code> nor
<code>C.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals <code>C.static_extent(0)</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(8.3)</a></span> if
neither <code>B.static_extent(1)</code> nor
<code>C.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>B.static_extent(1)</code> equals
<code>C.static_extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>A.extent(0)</code> times
<code>B.extent(1)</code> times <code>A.extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span> The
following requirements apply to all overloads of
<code>hermitian_matrix_right_product</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.1)</a></span>
<code>B.extent(1)</code> equals <code>A.extent(0)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.2)</a></span>
<code>B.extent(0)</code> equals <code>C.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.3)</a></span>
<code>A.extent(1)</code> equals <code>C.extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.1)</a></span> If
neither <code>B.static_extent(1)</code> nor
<code>A.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>B.static_extent(1)</code> equals
<code>A.static_extent(0)</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.2)</a></span> if
neither <code>B.static_extent(0)</code> nor
<code>C.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>B.static_extent(0)</code> equals <code>C.static_extent(0)</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.3)</a></span> if
neither <code>A.static_extent(1)</code> nor
<code>C.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>C.static_extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">13</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>B.extent(0)</code> times
<code>A.extent(1)</code> times <code>B.extent(1)</code>.</p>
<h5 data-number="16.10.4.3.1" id="overwriting-hermitian-matrix-matrix-left-product-linalg.algs.blas3.hemm.ov.left"><span class="header-section-number">16.10.4.3.1</span> Overwriting Hermitian
matrix-matrix left product [linalg.algs.blas3.hemm.ov.left]<a href="#overwriting-hermitian-matrix-matrix-left-product-linalg.algs.blas3.hemm.ov.left" class="self-link"></a></h5>
<div class="sourceCode" id="cb129"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb129-1"><a href="#cb129-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb129-2"><a href="#cb129-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb129-3"><a href="#cb129-3" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb129-4"><a href="#cb129-4" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb129-5"><a href="#cb129-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_left_product<span class="op">(</span></span>
<span id="cb129-6"><a href="#cb129-6" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb129-7"><a href="#cb129-7" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb129-8"><a href="#cb129-8" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb129-9"><a href="#cb129-9" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb129-10"><a href="#cb129-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb129-11"><a href="#cb129-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb129-12"><a href="#cb129-12" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb129-13"><a href="#cb129-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb129-14"><a href="#cb129-14" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb129-15"><a href="#cb129-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_left_product<span class="op">(</span></span>
<span id="cb129-16"><a href="#cb129-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb129-17"><a href="#cb129-17" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb129-18"><a href="#cb129-18" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb129-19"><a href="#cb129-19" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb129-20"><a href="#cb129-20" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>A</em><em>B</em></span>.</p>
<h5 data-number="16.10.4.3.2" id="overwriting-hermitian-matrix-matrix-right-product-linalg.algs.blas3.hemm.ov.right"><span class="header-section-number">16.10.4.3.2</span> Overwriting Hermitian
matrix-matrix right product [linalg.algs.blas3.hemm.ov.right]<a href="#overwriting-hermitian-matrix-matrix-right-product-linalg.algs.blas3.hemm.ov.right" class="self-link"></a></h5>
<div class="sourceCode" id="cb130"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb130-1"><a href="#cb130-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb130-2"><a href="#cb130-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb130-3"><a href="#cb130-3" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb130-4"><a href="#cb130-4" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb130-5"><a href="#cb130-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_right_product<span class="op">(</span></span>
<span id="cb130-6"><a href="#cb130-6" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb130-7"><a href="#cb130-7" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb130-8"><a href="#cb130-8" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb130-9"><a href="#cb130-9" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb130-10"><a href="#cb130-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb130-11"><a href="#cb130-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb130-12"><a href="#cb130-12" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb130-13"><a href="#cb130-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb130-14"><a href="#cb130-14" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb130-15"><a href="#cb130-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_right_product<span class="op">(</span></span>
<span id="cb130-16"><a href="#cb130-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb130-17"><a href="#cb130-17" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb130-18"><a href="#cb130-18" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb130-19"><a href="#cb130-19" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb130-20"><a href="#cb130-20" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>B</em><em>A</em></span>.</p>
<h5 data-number="16.10.4.3.3" id="updating-hermitian-matrix-matrix-left-product-linalg.algs.blas3.hemm.up.left"><span class="header-section-number">16.10.4.3.3</span> Updating Hermitian
matrix-matrix left product [linalg.algs.blas3.hemm.up.left]<a href="#updating-hermitian-matrix-matrix-left-product-linalg.algs.blas3.hemm.up.left" class="self-link"></a></h5>
<div class="sourceCode" id="cb131"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb131-1"><a href="#cb131-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb131-2"><a href="#cb131-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb131-3"><a href="#cb131-3" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb131-4"><a href="#cb131-4" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb131-5"><a href="#cb131-5" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb131-6"><a href="#cb131-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_left_product<span class="op">(</span></span>
<span id="cb131-7"><a href="#cb131-7" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb131-8"><a href="#cb131-8" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb131-9"><a href="#cb131-9" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb131-10"><a href="#cb131-10" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb131-11"><a href="#cb131-11" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb131-12"><a href="#cb131-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb131-13"><a href="#cb131-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb131-14"><a href="#cb131-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb131-15"><a href="#cb131-15" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb131-16"><a href="#cb131-16" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb131-17"><a href="#cb131-17" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb131-18"><a href="#cb131-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_left_product<span class="op">(</span></span>
<span id="cb131-19"><a href="#cb131-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb131-20"><a href="#cb131-20" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb131-21"><a href="#cb131-21" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb131-22"><a href="#cb131-22" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb131-23"><a href="#cb131-23" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb131-24"><a href="#cb131-24" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>E</em> + <em>A</em><em>B</em></span>.</p>
<h5 data-number="16.10.4.3.4" id="updating-hermitian-matrix-matrix-right-product-linalg.algs.blas3.hemm.up.right"><span class="header-section-number">16.10.4.3.4</span> Updating Hermitian
matrix-matrix right product [linalg.algs.blas3.hemm.up.right]<a href="#updating-hermitian-matrix-matrix-right-product-linalg.algs.blas3.hemm.up.right" class="self-link"></a></h5>
<div class="sourceCode" id="cb132"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb132-1"><a href="#cb132-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb132-2"><a href="#cb132-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb132-3"><a href="#cb132-3" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb132-4"><a href="#cb132-4" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb132-5"><a href="#cb132-5" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb132-6"><a href="#cb132-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_right_product<span class="op">(</span></span>
<span id="cb132-7"><a href="#cb132-7" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb132-8"><a href="#cb132-8" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb132-9"><a href="#cb132-9" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb132-10"><a href="#cb132-10" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb132-11"><a href="#cb132-11" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb132-12"><a href="#cb132-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb132-13"><a href="#cb132-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb132-14"><a href="#cb132-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb132-15"><a href="#cb132-15" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb132-16"><a href="#cb132-16" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb132-17"><a href="#cb132-17" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb132-18"><a href="#cb132-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_right_product<span class="op">(</span></span>
<span id="cb132-19"><a href="#cb132-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb132-20"><a href="#cb132-20" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb132-21"><a href="#cb132-21" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb132-22"><a href="#cb132-22" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb132-23"><a href="#cb132-23" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb132-24"><a href="#cb132-24" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>E</em> + <em>B</em><em>A</em></span>.</p>
<h4 data-number="16.10.4.4" id="triangular-matrix-matrix-product-linalg.algs.blas3.trmm"><span class="header-section-number">16.10.4.4</span> Triangular matrix-matrix
product [linalg.algs.blas3.trmm]<a href="#triangular-matrix-matrix-product-linalg.algs.blas3.trmm" class="self-link"></a></h4>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xTRMM</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following requirements apply to all functions in this section.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>C.extent(0)</code> equals <code>E.extent(0)</code> (if
applicable), and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<code>C.extent(1)</code> equals <code>E.extent(1)</code> (if
applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Constraints:</em></p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
<code>InMat1</code> has <code>layout_blas_packed</code> layout, then the
layout’s <code>Triangle</code> template argument has the same type as
the function’s <code>Triangle</code> template argument.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>A.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>A.static_extent(1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> For
all <code>r</code> in 0, 1, …, <code>C.rank()</code> - 1, if neither
<code>C.static_extent(r)</code> nor <code>E.static_extent(r)</code>
equals <code>dynamic_extent</code>, then <code>C.static_extent(r)</code>
equals <code>E.static_extent(r)</code> (if applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Remarks:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span> The
functions will only access the triangle of <code>A</code> specified by
the <code>Triangle</code> argument <code>t</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span> If
the <code>DiagonalStorage</code> template argument has type
<code>implicit_unit_diagonal_t</code>, then the functions will not
access the diagonal of <code>A</code>, and will interpret <code>A</code>
as if each of its diagonal elements behaves as a two-sided
multiplicative identity.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.3)</a></span>
<code>C</code> and <code>E</code> (if applicable) may refer to the same
matrix.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
The following requirements apply to all overloads of
<code>triangular_matrix_left_product</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.1)</a></span>
<code>A.extent(1)</code> equals <code>B.extent(0)</code> (if
applicable),</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.2)</a></span>
<code>A.extent(0)</code> equals <code>C.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.3)</a></span>
<code>B.extent(1)</code> equals <code>C.extent(1)</code> (if
applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(8.1)</a></span> if
neither <code>A.static_extent(1)</code> nor
<code>B.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals <code>B.static_extent(0)</code>
(if applicable);</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(8.2)</a></span> if
neither <code>A.static_extent(0)</code> nor
<code>C.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals <code>C.static_extent(0)</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(8.3)</a></span> if
neither <code>B.static_extent(1)</code> nor
<code>C.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>B.static_extent(1)</code> equals <code>C.static_extent(1)</code>
(if applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>A.extent(0)</code> times
<code>B.extent(1)</code> times <code>A.extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span> The
following requirements apply to all overloads of
<code>triangular_matrix_right_product</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.1)</a></span>
<code>B.extent(1)</code> equals <code>A.extent(0)</code> (if
applicable),</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.2)</a></span>
<code>B.extent(0)</code> equals <code>C.extent(0)</code> (if
applicable), and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.3)</a></span>
<code>A.extent(1)</code> equals <code>C.extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.1)</a></span> if
neither <code>B.static_extent(1)</code> nor
<code>A.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>B.static_extent(1)</code> equals <code>A.static_extent(0)</code>
(if applicable);</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.2)</a></span> if
neither <code>B.static_extent(0)</code> nor
<code>C.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>B.static_extent(0)</code> equals <code>C.static_extent(0)</code>
(if applicable); and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.3)</a></span> if
neither <code>A.static_extent(1)</code> nor
<code>C.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>C.static_extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">13</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>B.extent(0)</code> times
<code>A.extent(1)</code> times <code>B.extent(1)</code>.</p>
<h5 data-number="16.10.4.4.1" id="overwriting-triangular-matrix-matrix-left-product-linalg.algs.blas3.trmm.ov.left"><span class="header-section-number">16.10.4.4.1</span> Overwriting triangular
matrix-matrix left product [linalg.algs.blas3.trmm.ov.left]<a href="#overwriting-triangular-matrix-matrix-left-product-linalg.algs.blas3.trmm.ov.left" class="self-link"></a></h5>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Not-in-place overwriting triangular matrix-matrix left product</p>
<div class="sourceCode" id="cb133"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb133-1"><a href="#cb133-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb133-2"><a href="#cb133-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb133-3"><a href="#cb133-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb133-4"><a href="#cb133-4" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb133-5"><a href="#cb133-5" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb133-6"><a href="#cb133-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_left_product<span class="op">(</span></span>
<span id="cb133-7"><a href="#cb133-7" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb133-8"><a href="#cb133-8" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb133-9"><a href="#cb133-9" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb133-10"><a href="#cb133-10" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb133-11"><a href="#cb133-11" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb133-12"><a href="#cb133-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb133-13"><a href="#cb133-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb133-14"><a href="#cb133-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb133-15"><a href="#cb133-15" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb133-16"><a href="#cb133-16" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb133-17"><a href="#cb133-17" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb133-18"><a href="#cb133-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_left_product<span class="op">(</span></span>
<span id="cb133-19"><a href="#cb133-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb133-20"><a href="#cb133-20" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb133-21"><a href="#cb133-21" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb133-22"><a href="#cb133-22" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb133-23"><a href="#cb133-23" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb133-24"><a href="#cb133-24" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>A</em><em>B</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
In-place overwriting triangular matrix-matrix left product</p>
<div class="sourceCode" id="cb134"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb134-1"><a href="#cb134-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb134-2"><a href="#cb134-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb134-3"><a href="#cb134-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb134-4"><a href="#cb134-4" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb134-5"><a href="#cb134-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_left_product<span class="op">(</span></span>
<span id="cb134-6"><a href="#cb134-6" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb134-7"><a href="#cb134-7" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb134-8"><a href="#cb134-8" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb134-9"><a href="#cb134-9" aria-hidden="true" tabindex="-1"></a>  InOutMat C<span class="op">)</span>;</span>
<span id="cb134-10"><a href="#cb134-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb134-11"><a href="#cb134-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb134-12"><a href="#cb134-12" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb134-13"><a href="#cb134-13" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb134-14"><a href="#cb134-14" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb134-15"><a href="#cb134-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_left_product<span class="op">(</span></span>
<span id="cb134-16"><a href="#cb134-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb134-17"><a href="#cb134-17" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb134-18"><a href="#cb134-18" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb134-19"><a href="#cb134-19" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb134-20"><a href="#cb134-20" aria-hidden="true" tabindex="-1"></a>  InOutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Preconditions:</em> <code>A.extent(1)</code> equals
<code>C.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Mandates:</em> If neither <code>A.static_extent(1)</code> nor
<code>C.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>C.static_extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Effects:</em> Overwrites <span class="math inline"><em>C</em></span>
with <span class="math inline"><em>C</em>′</span> such that <span class="math inline"><em>C</em>′ = <em>A</em><em>C</em></span>.</p>
<h5 data-number="16.10.4.4.2" id="overwriting-triangular-matrix-matrix-right-product-linalg.algs.blas3.trmm.ov.right"><span class="header-section-number">16.10.4.4.2</span> Overwriting triangular
matrix-matrix right product [linalg.algs.blas3.trmm.ov.right]<a href="#overwriting-triangular-matrix-matrix-right-product-linalg.algs.blas3.trmm.ov.right" class="self-link"></a></h5>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Not-in-place overwriting triangular matrix-matrix right product</p>
<div class="sourceCode" id="cb135"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb135-1"><a href="#cb135-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb135-2"><a href="#cb135-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb135-3"><a href="#cb135-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb135-4"><a href="#cb135-4" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb135-5"><a href="#cb135-5" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb135-6"><a href="#cb135-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_right_product<span class="op">(</span></span>
<span id="cb135-7"><a href="#cb135-7" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb135-8"><a href="#cb135-8" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb135-9"><a href="#cb135-9" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb135-10"><a href="#cb135-10" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb135-11"><a href="#cb135-11" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb135-12"><a href="#cb135-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb135-13"><a href="#cb135-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb135-14"><a href="#cb135-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb135-15"><a href="#cb135-15" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb135-16"><a href="#cb135-16" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb135-17"><a href="#cb135-17" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb135-18"><a href="#cb135-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_right_product<span class="op">(</span></span>
<span id="cb135-19"><a href="#cb135-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb135-20"><a href="#cb135-20" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb135-21"><a href="#cb135-21" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb135-22"><a href="#cb135-22" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb135-23"><a href="#cb135-23" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb135-24"><a href="#cb135-24" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>B</em><em>A</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
In-place overwriting triangular matrix-matrix right product</p>
<div class="sourceCode" id="cb136"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb136-1"><a href="#cb136-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb136-2"><a href="#cb136-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb136-3"><a href="#cb136-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb136-4"><a href="#cb136-4" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb136-5"><a href="#cb136-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_right_product<span class="op">(</span></span>
<span id="cb136-6"><a href="#cb136-6" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb136-7"><a href="#cb136-7" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb136-8"><a href="#cb136-8" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb136-9"><a href="#cb136-9" aria-hidden="true" tabindex="-1"></a>  InOutMat C<span class="op">)</span>;</span>
<span id="cb136-10"><a href="#cb136-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb136-11"><a href="#cb136-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb136-12"><a href="#cb136-12" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb136-13"><a href="#cb136-13" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb136-14"><a href="#cb136-14" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb136-15"><a href="#cb136-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_right_product<span class="op">(</span></span>
<span id="cb136-16"><a href="#cb136-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb136-17"><a href="#cb136-17" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb136-18"><a href="#cb136-18" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb136-19"><a href="#cb136-19" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb136-20"><a href="#cb136-20" aria-hidden="true" tabindex="-1"></a>  InOutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Preconditions:</em> <code>C.extent(1)</code> equals
<code>A.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Mandates:</em> If neither <code>C.static_extent(1)</code> nor
<code>A.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>C.static_extent(1)</code> equals
<code>A.static_extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Effects:</em> Overwrites <span class="math inline"><em>C</em></span>
with <span class="math inline"><em>C</em>′</span> such that <span class="math inline"><em>C</em>′ = <em>C</em><em>A</em></span>.</p>
<h5 data-number="16.10.4.4.3" id="updating-triangular-matrix-matrix-left-product-linalg.algs.blas3.trmm.up.left"><span class="header-section-number">16.10.4.4.3</span> Updating triangular
matrix-matrix left product [linalg.algs.blas3.trmm.up.left]<a href="#updating-triangular-matrix-matrix-left-product-linalg.algs.blas3.trmm.up.left" class="self-link"></a></h5>
<div class="sourceCode" id="cb137"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb137-1"><a href="#cb137-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb137-2"><a href="#cb137-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb137-3"><a href="#cb137-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb137-4"><a href="#cb137-4" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb137-5"><a href="#cb137-5" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb137-6"><a href="#cb137-6" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb137-7"><a href="#cb137-7" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_left_product<span class="op">(</span></span>
<span id="cb137-8"><a href="#cb137-8" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb137-9"><a href="#cb137-9" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb137-10"><a href="#cb137-10" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb137-11"><a href="#cb137-11" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb137-12"><a href="#cb137-12" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb137-13"><a href="#cb137-13" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb137-14"><a href="#cb137-14" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb137-15"><a href="#cb137-15" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb137-16"><a href="#cb137-16" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb137-17"><a href="#cb137-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb137-18"><a href="#cb137-18" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb137-19"><a href="#cb137-19" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb137-20"><a href="#cb137-20" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb137-21"><a href="#cb137-21" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_left_product<span class="op">(</span></span>
<span id="cb137-22"><a href="#cb137-22" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb137-23"><a href="#cb137-23" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb137-24"><a href="#cb137-24" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb137-25"><a href="#cb137-25" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb137-26"><a href="#cb137-26" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb137-27"><a href="#cb137-27" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb137-28"><a href="#cb137-28" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>E</em> + <em>A</em><em>B</em></span>.</p>
<h5 data-number="16.10.4.4.4" id="updating-triangular-matrix-matrix-right-product-linalg.algs.blas3.trmm.up.right"><span class="header-section-number">16.10.4.4.4</span> Updating triangular
matrix-matrix right product [linalg.algs.blas3.trmm.up.right]<a href="#updating-triangular-matrix-matrix-right-product-linalg.algs.blas3.trmm.up.right" class="self-link"></a></h5>
<div class="sourceCode" id="cb138"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb138-1"><a href="#cb138-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb138-2"><a href="#cb138-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb138-3"><a href="#cb138-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb138-4"><a href="#cb138-4" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb138-5"><a href="#cb138-5" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb138-6"><a href="#cb138-6" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb138-7"><a href="#cb138-7" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_right_product<span class="op">(</span></span>
<span id="cb138-8"><a href="#cb138-8" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb138-9"><a href="#cb138-9" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb138-10"><a href="#cb138-10" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb138-11"><a href="#cb138-11" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb138-12"><a href="#cb138-12" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb138-13"><a href="#cb138-13" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span>
<span id="cb138-14"><a href="#cb138-14" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb138-15"><a href="#cb138-15" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb138-16"><a href="#cb138-16" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb138-17"><a href="#cb138-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb138-18"><a href="#cb138-18" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb138-19"><a href="#cb138-19" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb138-20"><a href="#cb138-20" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb138-21"><a href="#cb138-21" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_right_product<span class="op">(</span></span>
<span id="cb138-22"><a href="#cb138-22" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb138-23"><a href="#cb138-23" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb138-24"><a href="#cb138-24" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb138-25"><a href="#cb138-25" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb138-26"><a href="#cb138-26" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb138-27"><a href="#cb138-27" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb138-28"><a href="#cb138-28" aria-hidden="true" tabindex="-1"></a>  OutMat C<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em></span>
such that <span class="math inline"><em>C</em> = <em>E</em> + <em>B</em><em>A</em></span>.</p>
<h4 data-number="16.10.4.5" id="rank-k-update-of-a-symmetric-or-hermitian-matrix-linalg.alg.blas3.rank-k"><span class="header-section-number">16.10.4.5</span> Rank-k update of a
symmetric or Hermitian matrix [linalg.alg.blas3.rank-k]<a href="#rank-k-update-of-a-symmetric-or-hermitian-matrix-linalg.alg.blas3.rank-k" class="self-link"></a></h4>
<p><i>[Note:</i> Users can achieve the effect of the <code>TRANS</code>
argument of these BLAS functions, by applying <code>transposed</code> or
<code>conjugate_transposed</code> to the input matrix. <i>– end
note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Complexity:</em> For all algorithms in this Clause, the count of
<code>mdspan</code> array accesses and arithmetic operations is linear
in <code>A.extent(0)</code> times <code>A.extent(1)</code> times
<code>A.extent(0)</code>.</p>
<h5 data-number="16.10.4.5.1" id="rank-k-symmetric-matrix-update-linalg.alg.blas3.rank-k.syrk"><span class="header-section-number">16.10.4.5.1</span> Rank-k symmetric matrix
update [linalg.alg.blas3.rank-k.syrk]<a href="#rank-k-symmetric-matrix-update-linalg.alg.blas3.rank-k.syrk" class="self-link"></a></h5>
<div class="sourceCode" id="cb139"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb139-1"><a href="#cb139-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T,</span>
<span id="cb139-2"><a href="#cb139-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb139-3"><a href="#cb139-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb139-4"><a href="#cb139-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb139-5"><a href="#cb139-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb139-6"><a href="#cb139-6" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb139-7"><a href="#cb139-7" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb139-8"><a href="#cb139-8" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb139-9"><a href="#cb139-9" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb139-10"><a href="#cb139-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb139-11"><a href="#cb139-11" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T,</span>
<span id="cb139-12"><a href="#cb139-12" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb139-13"><a href="#cb139-13" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb139-14"><a href="#cb139-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb139-15"><a href="#cb139-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb139-16"><a href="#cb139-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb139-17"><a href="#cb139-17" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb139-18"><a href="#cb139-18" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb139-19"><a href="#cb139-19" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb139-20"><a href="#cb139-20" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xSYRK</code>.</p>
<p>They take a scaling factor <code>alpha</code>, because it would be
impossible to express the update <span class="math inline"><em>C</em> = <em>C</em> − <em>A</em><em>A</em><sup><em>T</em></sup></span>
otherwise. The scaling factor parameter is required in order to avoid
ambiguity with <code>ExecutionPolicy</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>A.extent(0)</code> equals <code>C.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>C.extent(0)</code> equals <code>C.extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> If <code>C</code> has
<code>layout_blas_packed</code> layout, then the layout’s
<code>Triangle</code> template argument has the same type as the
function’s <code>Triangle</code> template argument.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>C.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>C.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> If
neither <code>C.static_extent(0)</code> nor
<code>C.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>C.static_extent(0)</code> equals
<code>C.static_extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em> Overwrites <span class="math inline"><em>C</em></span>
with <span class="math inline"><em>C</em>′</span> such that <span class="math inline"><em>C</em>′ = <em>C</em> + <em>α</em><em>A</em><em>A</em><sup><em>T</em></sup></span>,
where the scalar <span class="math inline"><em>α</em></span> is
<code>alpha</code> and <span class="math inline"><em>A</em><sup><em>T</em></sup></span> denotes the
transpose of the matrix <span class="math inline"><em>A</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Remarks:</em> The functions will only access the triangle of
<code>C</code> specified by the <code>Triangle</code> argument
<code>t</code>, and will interpret the value <code>C[i,j]</code> as
equal to <code>C[j,i]</code> for indices <code>i,j</code> in the domain
of <code>C</code> but outside the triangle specified by
<code>t</code>.</p>
<h5 data-number="16.10.4.5.2" id="rank-k-hermitian-matrix-update-linalg.alg.blas3.rank-k.herk"><span class="header-section-number">16.10.4.5.2</span> Rank-k Hermitian matrix
update [linalg.alg.blas3.rank-k.herk]<a href="#rank-k-hermitian-matrix-update-linalg.alg.blas3.rank-k.herk" class="self-link"></a></h5>
<div class="sourceCode" id="cb140"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb140-1"><a href="#cb140-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T,</span>
<span id="cb140-2"><a href="#cb140-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb140-3"><a href="#cb140-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb140-4"><a href="#cb140-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb140-5"><a href="#cb140-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb140-6"><a href="#cb140-6" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb140-7"><a href="#cb140-7" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb140-8"><a href="#cb140-8" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb140-9"><a href="#cb140-9" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb140-10"><a href="#cb140-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb140-11"><a href="#cb140-11" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T,</span>
<span id="cb140-12"><a href="#cb140-12" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb140-13"><a href="#cb140-13" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb140-14"><a href="#cb140-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb140-15"><a href="#cb140-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb140-16"><a href="#cb140-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb140-17"><a href="#cb140-17" aria-hidden="true" tabindex="-1"></a>  T alpha,</span>
<span id="cb140-18"><a href="#cb140-18" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb140-19"><a href="#cb140-19" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb140-20"><a href="#cb140-20" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xHERK</code>.</p>
<p>They take a scaling factor <code>alpha</code>, because it would be
impossible to express the updates <span class="math inline"><em>C</em> = <em>C</em> − <em>A</em><em>A</em><sup><em>T</em></sup></span>
or <span class="math inline"><em>C</em> = <em>C</em> − <em>A</em><em>A</em><sup><em>H</em></sup></span>
otherwise. The scaling factor parameter is required in order to avoid
ambiguity with <code>ExecutionPolicy</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>A.extent(0)</code> equals <code>C.extent(0)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>C.extent(0)</code> equals <code>C.extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> If <code>C</code> has
<code>layout_blas_packed</code> layout, then the layout’s
<code>Triangle</code> template argument has the same type as the
function’s <code>Triangle</code> template argument.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>C.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>C.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> If
neither <code>C.static_extent(0)</code> nor
<code>C.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>C.static_extent(0)</code> equals
<code>C.static_extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em> Overwrites <span class="math inline"><em>C</em></span>
with <span class="math inline"><em>C</em>′</span> such that <span class="math inline"><em>C</em>′ = <em>C</em> + <em>α</em><em>A</em><em>A</em><sup><em>H</em></sup></span>,
where the scalar <span class="math inline"><em>α</em></span> is
<code>alpha</code> and <span class="math inline"><em>A</em><sup><em>H</em></sup></span> denotes the
conjugate transpose of the matrix <span class="math inline"><em>A</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Remarks:</em> The functions will only access the triangle of
<code>C</code> specified by the <code>Triangle</code> argument
<code>t</code>, and will interpret the value <code>C[i,j]</code> as
equal to <code>C[j,i]</code> for indices <code>i,j</code> in the domain
of <code>C</code> but outside the triangle specified by
<code>t</code>.</p>
<h4 data-number="16.10.4.6" id="rank-2k-update-of-a-symmetric-or-hermitian-matrix-linalg.alg.blas3.rank2k"><span class="header-section-number">16.10.4.6</span> Rank-2k update of a
symmetric or Hermitian matrix [linalg.alg.blas3.rank2k]<a href="#rank-2k-update-of-a-symmetric-or-hermitian-matrix-linalg.alg.blas3.rank2k" class="self-link"></a></h4>
<p><i>[Note:</i> Users can achieve the effect of the <code>TRANS</code>
argument of these BLAS functions, by applying <code>transposed</code> or
<code>conjugate_transposed</code> to the input matrices. <i>– end
note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>A.extent(0)</code> times
<code>A.extent(1)</code> times <code>B.extent(1)</code>.</p>
<h5 data-number="16.10.4.6.1" id="rank-2k-symmetric-matrix-update-linalg.alg.blas3.rank2k.syr2k"><span class="header-section-number">16.10.4.6.1</span> Rank-2k symmetric
matrix update [linalg.alg.blas3.rank2k.syr2k]<a href="#rank-2k-symmetric-matrix-update-linalg.alg.blas3.rank2k.syr2k" class="self-link"></a></h5>
<div class="sourceCode" id="cb141"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb141-1"><a href="#cb141-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb141-2"><a href="#cb141-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb141-3"><a href="#cb141-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb141-4"><a href="#cb141-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb141-5"><a href="#cb141-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb141-6"><a href="#cb141-6" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb141-7"><a href="#cb141-7" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb141-8"><a href="#cb141-8" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb141-9"><a href="#cb141-9" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb141-10"><a href="#cb141-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb141-11"><a href="#cb141-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb141-12"><a href="#cb141-12" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb141-13"><a href="#cb141-13" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb141-14"><a href="#cb141-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb141-15"><a href="#cb141-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb141-16"><a href="#cb141-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb141-17"><a href="#cb141-17" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb141-18"><a href="#cb141-18" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb141-19"><a href="#cb141-19" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb141-20"><a href="#cb141-20" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xSYR2K</code>. The BLAS “quick reference” has a typo; the “ALPHA”
argument of <code>CSYR2K</code> and <code>ZSYR2K</code> should not be
conjugated. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>A.extent(0)</code> equals <code>B.extent(0)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>A.extent(1)</code> equals <code>B.extent(1)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
<code>A.extent(0)</code> equals <code>C.extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> If <code>C</code> has
<code>layout_blas_packed</code> layout, then the layout’s
<code>Triangle</code> template argument has the same type as the
function’s <code>Triangle</code> template argument.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>B.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>B.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> If
neither <code>A.static_extent(1)</code> nor
<code>B.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>B.static_extent(1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>C.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>C.static_extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em> Overwrites <span class="math inline"><em>C</em></span>
with <span class="math inline"><em>C</em>′</span> such that <span class="math inline"><em>C</em>′ = <em>C</em> + <em>A</em><em>B</em><sup><em>T</em></sup> + <em>B</em><em>A</em><sup><em>T</em></sup></span>,
where <span class="math inline"><em>A</em><sup><em>T</em></sup></span>
denotes the transpose of the matrix <span class="math inline"><em>A</em></span> and <span class="math inline"><em>B</em><sup><em>T</em></sup></span> denotes the
transpose of the matrix <span class="math inline"><em>B</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Remarks:</em> The functions will only access the triangle of
<code>C</code> specified by the <code>Triangle</code> argument
<code>t</code>, and will interpret the value <code>C[i,j]</code> as
equal to <code>C[j,i]</code> for indices <code>i,j</code> in the domain
of <code>C</code> but outside the triangle specified by
<code>t</code>.</p>
<h5 data-number="16.10.4.6.2" id="rank-2k-hermitian-matrix-update-linalg.alg.blas3.rank2k.her2k"><span class="header-section-number">16.10.4.6.2</span> Rank-2k Hermitian
matrix update [linalg.alg.blas3.rank2k.her2k]<a href="#rank-2k-hermitian-matrix-update-linalg.alg.blas3.rank2k.her2k" class="self-link"></a></h5>
<div class="sourceCode" id="cb142"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb142-1"><a href="#cb142-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb142-2"><a href="#cb142-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb142-3"><a href="#cb142-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb142-4"><a href="#cb142-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb142-5"><a href="#cb142-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb142-6"><a href="#cb142-6" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb142-7"><a href="#cb142-7" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb142-8"><a href="#cb142-8" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb142-9"><a href="#cb142-9" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb142-10"><a href="#cb142-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb142-11"><a href="#cb142-11" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb142-12"><a href="#cb142-12" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb142-13"><a href="#cb142-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb142-14"><a href="#cb142-14" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-inout-matrix</em> InOutMat,</span>
<span id="cb142-15"><a href="#cb142-15" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb142-16"><a href="#cb142-16" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb142-17"><a href="#cb142-17" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb142-18"><a href="#cb142-18" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb142-19"><a href="#cb142-19" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb142-20"><a href="#cb142-20" aria-hidden="true" tabindex="-1"></a>  InOutMat C,</span>
<span id="cb142-21"><a href="#cb142-21" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xHER2K</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>A.extent(0)</code> equals <code>B.extent(0)</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>A.extent(1)</code> equals <code>B.extent(1)</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
<code>A.extent(0)</code> equals <code>C.extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> If <code>C</code> has
<code>layout_blas_packed</code> layout, then the layout’s
<code>Triangle</code> template argument has the same type as the
function’s <code>Triangle</code> template argument.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>B.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>B.static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> If
neither <code>A.static_extent(1)</code> nor
<code>B.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>B.static_extent(1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>C.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>C.static_extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Effects:</em> Overwrites <span class="math inline"><em>C</em></span>
with <span class="math inline"><em>C</em>′</span> such that <span class="math inline"><em>C</em>′ = <em>C</em> + <em>A</em><em>B</em><sup><em>H</em></sup> + <em>B</em><em>A</em><sup><em>H</em></sup></span>,
where <span class="math inline"><em>A</em><sup><em>H</em></sup></span>
denotes the conjugate transpose of the matrix <span class="math inline"><em>A</em></span> and <span class="math inline"><em>B</em><sup><em>H</em></sup></span> denotes the
conjugate transpose of the matrix <span class="math inline"><em>B</em></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Remarks:</em> The functions will only access the triangle of
<code>C</code> specified by the <code>Triangle</code> argument
<code>t</code>, and will interpret the value <code>C[i,j]</code> as
equal to <em><code>conj-if-needed</code></em><code>(C[j,i])</code> for
indices <code>i,j</code> in the domain of <code>C</code> but outside the
triangle specified by <code>t</code>.</p>
<h4 data-number="16.10.4.7" id="solve-multiple-triangular-linear-systems-linalg.alg.blas3.trsm"><span class="header-section-number">16.10.4.7</span> Solve multiple triangular
linear systems [linalg.alg.blas3.trsm]<a href="#solve-multiple-triangular-linear-systems-linalg.alg.blas3.trsm" class="self-link"></a></h4>
<p><i>[Note:</i> These functions correspond to the BLAS function
<code>xTRSM</code>. The Reference BLAS does not have a
<code>xTPSM</code> function. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following requirements apply to all functions in this section.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> For
all <code>r</code> in 0, 1, …, <code>B.rank()</code> - 1,
<code>X.extent(r)</code> equals <code>B.extent(r)</code> (if
applicable); and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> if
<code>r,j</code> is in the domain of <code>X</code> and <code>B</code>,
then the expression <code>X[r,j] = B[r,j]</code> is well formed (if
applicable); and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> if
<code>DiagonalStorage</code> is <code>explicit_diagonal_t</code>, and
<code>i,j</code> is in the domain of <code>X</code>, then the expression
<code>X[i,j] /= A[i,i]</code> is well formed (if applicable).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> For
all <code>r</code> in 0, 1, …, <code>X.rank()</code> - 1, if neither
<code>X.static_extent(r)</code> nor <code>B.static_extent(r)</code>
equals <code>dynamic_extent</code>, then <code>X.static_extent(r)</code>
equals <code>B.static_extent(r)</code> (if applicable).</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> If
neither <code>A.static_extent(0)</code> nor
<code>A.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(0)</code> equals
<code>A.static_extent(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Remarks:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span> The
functions will only access the triangle of <code>A</code> specified by
the <code>Triangle</code> argument <code>t</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span> If
the <code>DiagonalStorage</code> template argument has type
<code>implicit_unit_diagonal_t</code>, then the functions will not
access the diagonal of <code>A</code>, and will interpret <code>A</code>
as if each of its diagonal elements behaves as a two-sided
multiplicative identity.</p></li>
</ul>
<h5 data-number="16.10.4.7.1" id="solve-multiple-triangular-linear-systems-with-triangular-matrix-on-the-left-linalg.alg.blas3.trsm.left"><span class="header-section-number">16.10.4.7.1</span> Solve multiple
triangular linear systems with triangular matrix on the left
[linalg.alg.blas3.trsm.left]<a href="#solve-multiple-triangular-linear-systems-with-triangular-matrix-on-the-left-linalg.alg.blas3.trsm.left" class="self-link"></a></h5>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>A.extent(0)</code> times
<code>A.extent(1)</code> times <code>X.extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Not-in-place left solve of multiple triangular systems</p>
<div class="sourceCode" id="cb143"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb143-1"><a href="#cb143-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb143-2"><a href="#cb143-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb143-3"><a href="#cb143-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb143-4"><a href="#cb143-4" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb143-5"><a href="#cb143-5" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat,</span>
<span id="cb143-6"><a href="#cb143-6" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb143-7"><a href="#cb143-7" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb143-8"><a href="#cb143-8" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb143-9"><a href="#cb143-9" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb143-10"><a href="#cb143-10" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb143-11"><a href="#cb143-11" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb143-12"><a href="#cb143-12" aria-hidden="true" tabindex="-1"></a>  OutMat X,</span>
<span id="cb143-13"><a href="#cb143-13" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb143-14"><a href="#cb143-14" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb143-15"><a href="#cb143-15" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb143-16"><a href="#cb143-16" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb143-17"><a href="#cb143-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb143-18"><a href="#cb143-18" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb143-19"><a href="#cb143-19" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat,</span>
<span id="cb143-20"><a href="#cb143-20" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb143-21"><a href="#cb143-21" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb143-22"><a href="#cb143-22" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb143-23"><a href="#cb143-23" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb143-24"><a href="#cb143-24" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb143-25"><a href="#cb143-25" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb143-26"><a href="#cb143-26" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb143-27"><a href="#cb143-27" aria-hidden="true" tabindex="-1"></a>  OutMat X,</span>
<span id="cb143-28"><a href="#cb143-28" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb143-29"><a href="#cb143-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb143-30"><a href="#cb143-30" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb143-31"><a href="#cb143-31" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb143-32"><a href="#cb143-32" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb143-33"><a href="#cb143-33" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb143-34"><a href="#cb143-34" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb143-35"><a href="#cb143-35" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb143-36"><a href="#cb143-36" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb143-37"><a href="#cb143-37" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb143-38"><a href="#cb143-38" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb143-39"><a href="#cb143-39" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb143-40"><a href="#cb143-40" aria-hidden="true" tabindex="-1"></a>  OutMat X<span class="op">)</span>;</span>
<span id="cb143-41"><a href="#cb143-41" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb143-42"><a href="#cb143-42" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb143-43"><a href="#cb143-43" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb143-44"><a href="#cb143-44" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb143-45"><a href="#cb143-45" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb143-46"><a href="#cb143-46" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb143-47"><a href="#cb143-47" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb143-48"><a href="#cb143-48" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb143-49"><a href="#cb143-49" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb143-50"><a href="#cb143-50" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb143-51"><a href="#cb143-51" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb143-52"><a href="#cb143-52" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb143-53"><a href="#cb143-53" aria-hidden="true" tabindex="-1"></a>  OutMat X<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Preconditions:</em> <code>A.extent(1)</code> equals
<code>B.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates:</em> If neither <code>A.static_extent(1)</code> nor
<code>B.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>B.static_extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>X</em></span>
such that <span class="math inline"><em>A</em><em>X</em> = <em>B</em></span>. If so such
<span class="math inline"><em>X</em></span> exists, then the elements of
<span class="math inline"><em>X</em></span> are valid but
unspecified.</p>
<p><i>[Note:</i> Since the triangular matrix is on the left, the desired
<code>divide</code> implementation in the case of noncommutative
multiplication would be mathematically equivalent to the product of (the
inverse of the second argument) and the first argument, in that order.
<i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
In-place left solve of multiple triangular systems</p>
<div class="sourceCode" id="cb144"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb144-1"><a href="#cb144-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb144-2"><a href="#cb144-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb144-3"><a href="#cb144-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb144-4"><a href="#cb144-4" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat,</span>
<span id="cb144-5"><a href="#cb144-5" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb144-6"><a href="#cb144-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb144-7"><a href="#cb144-7" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb144-8"><a href="#cb144-8" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb144-9"><a href="#cb144-9" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb144-10"><a href="#cb144-10" aria-hidden="true" tabindex="-1"></a>  InOutMat B,</span>
<span id="cb144-11"><a href="#cb144-11" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb144-12"><a href="#cb144-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb144-13"><a href="#cb144-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb144-14"><a href="#cb144-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb144-15"><a href="#cb144-15" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb144-16"><a href="#cb144-16" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat,</span>
<span id="cb144-17"><a href="#cb144-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb144-18"><a href="#cb144-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb144-19"><a href="#cb144-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb144-20"><a href="#cb144-20" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb144-21"><a href="#cb144-21" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb144-22"><a href="#cb144-22" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb144-23"><a href="#cb144-23" aria-hidden="true" tabindex="-1"></a>  InOutMat B,</span>
<span id="cb144-24"><a href="#cb144-24" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb144-25"><a href="#cb144-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb144-26"><a href="#cb144-26" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb144-27"><a href="#cb144-27" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb144-28"><a href="#cb144-28" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb144-29"><a href="#cb144-29" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb144-30"><a href="#cb144-30" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb144-31"><a href="#cb144-31" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb144-32"><a href="#cb144-32" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb144-33"><a href="#cb144-33" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb144-34"><a href="#cb144-34" aria-hidden="true" tabindex="-1"></a>  InOutMat B<span class="op">)</span>;</span>
<span id="cb144-35"><a href="#cb144-35" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb144-36"><a href="#cb144-36" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb144-37"><a href="#cb144-37" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb144-38"><a href="#cb144-38" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb144-39"><a href="#cb144-39" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb144-40"><a href="#cb144-40" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_left_solve<span class="op">(</span></span>
<span id="cb144-41"><a href="#cb144-41" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb144-42"><a href="#cb144-42" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb144-43"><a href="#cb144-43" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb144-44"><a href="#cb144-44" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb144-45"><a href="#cb144-45" aria-hidden="true" tabindex="-1"></a>  InOutMat B<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> This algorithm makes it possible to compute
factorizations like Cholesky and LU in place.</p>
<p>Performing triangular solve in place hinders parallelization.
However, other <code>ExecutionPolicy</code>-specific optimizations, such
as vectorization, are still possible. This is why the
<code>ExecutionPolicy</code> overload exists. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Preconditions:</em> <code>A.extent(1)</code> equals
<code>B.extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Mandates:</em> If neither <code>A.static_extent(1)</code> nor
<code>B.static_extent(0)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>B.static_extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Effects:</em> Overwrites <span class="math inline"><em>B</em></span>
with <span class="math inline"><em>X</em></span> such that <span class="math inline"><em>A</em><em>X</em> = <em>B</em></span>. If no such
<span class="math inline"><em>X</em></span> exists, then the elements of
<span class="math inline"><em>X</em></span> are valid but
unspecified.</p>
<p><i>[Note:</i> Since the triangular matrix is on the left, the desired
<code>divide</code> implementation in the case of noncommutative
multiplication would be mathematically equivalent to the product of (the
inverse of the second argument) and the first argument, in that order.
<i>– end note]</i></p>
<h5 data-number="16.10.4.7.2" id="solve-multiple-triangular-linear-systems-with-triangular-matrix-on-the-right-linalg.alg.blas3.trsm.right"><span class="header-section-number">16.10.4.7.2</span> Solve multiple
triangular linear systems with triangular matrix on the right
[linalg.alg.blas3.trsm.right]<a href="#solve-multiple-triangular-linear-systems-with-triangular-matrix-on-the-right-linalg.alg.blas3.trsm.right" class="self-link"></a></h5>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Complexity:</em> The count of <code>mdspan</code> array accesses and
arithmetic operations is linear in <code>B.extent(0)</code> times
<code>B.extent(1)</code> times <code>A.extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Not-in-place right solve of multiple triangular systems</p>
<div class="sourceCode" id="cb145"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb145-1"><a href="#cb145-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb145-2"><a href="#cb145-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb145-3"><a href="#cb145-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb145-4"><a href="#cb145-4" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb145-5"><a href="#cb145-5" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat,</span>
<span id="cb145-6"><a href="#cb145-6" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb145-7"><a href="#cb145-7" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb145-8"><a href="#cb145-8" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb145-9"><a href="#cb145-9" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb145-10"><a href="#cb145-10" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb145-11"><a href="#cb145-11" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb145-12"><a href="#cb145-12" aria-hidden="true" tabindex="-1"></a>  OutMat X,</span>
<span id="cb145-13"><a href="#cb145-13" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb145-14"><a href="#cb145-14" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb145-15"><a href="#cb145-15" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb145-16"><a href="#cb145-16" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb145-17"><a href="#cb145-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb145-18"><a href="#cb145-18" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb145-19"><a href="#cb145-19" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat,</span>
<span id="cb145-20"><a href="#cb145-20" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb145-21"><a href="#cb145-21" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb145-22"><a href="#cb145-22" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb145-23"><a href="#cb145-23" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb145-24"><a href="#cb145-24" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb145-25"><a href="#cb145-25" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb145-26"><a href="#cb145-26" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb145-27"><a href="#cb145-27" aria-hidden="true" tabindex="-1"></a>  OutMat X,</span>
<span id="cb145-28"><a href="#cb145-28" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb145-29"><a href="#cb145-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb145-30"><a href="#cb145-30" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb145-31"><a href="#cb145-31" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb145-32"><a href="#cb145-32" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb145-33"><a href="#cb145-33" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb145-34"><a href="#cb145-34" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb145-35"><a href="#cb145-35" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb145-36"><a href="#cb145-36" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb145-37"><a href="#cb145-37" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb145-38"><a href="#cb145-38" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb145-39"><a href="#cb145-39" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb145-40"><a href="#cb145-40" aria-hidden="true" tabindex="-1"></a>  OutMat X<span class="op">)</span>;</span>
<span id="cb145-41"><a href="#cb145-41" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb145-42"><a href="#cb145-42" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb145-43"><a href="#cb145-43" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb145-44"><a href="#cb145-44" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb145-45"><a href="#cb145-45" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb145-46"><a href="#cb145-46" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb145-47"><a href="#cb145-47" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb145-48"><a href="#cb145-48" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb145-49"><a href="#cb145-49" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb145-50"><a href="#cb145-50" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb145-51"><a href="#cb145-51" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb145-52"><a href="#cb145-52" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb145-53"><a href="#cb145-53" aria-hidden="true" tabindex="-1"></a>  OutMat X<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> One can derive what these algorithms do from the
<code>triangular_matrix_matrix_left_solve()</code> algorithm, by
swapping the order of indices of each matrix access (representing the
transpose), swapping <code>i</code> and <code>j</code>, and swapping the
order of product terms in the sum. This is because
<code>triangular_matrix_matrix_left_solve()</code> solves AX = B, taking
the transpose of both sides does not change the equation, and the
transpose of a product of two matrices is the product of the reversed
matrices in transposed order. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Preconditions:</em> <code>A.extent(1)</code> equals
<code>B.extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates:</em> If neither <code>A.static_extent(1)</code> nor
<code>B.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>B.static_extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>X</em></span>
such that <span class="math inline"><em>X</em><em>A</em> = <em>B</em></span>. If so such
<span class="math inline"><em>X</em></span> exists, then the elements of
<span class="math inline"><em>X</em></span> are valid but
unspecified.</p>
<p><i>[Note:</i> Since the triangular matrix is on the right, the
desired <code>divide</code> implementation in the case of noncommutative
multiplication would be mathematically equivalent to the product of the
first argument, and (the inverse of the second argument), in that order.
<i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
In-place right solve of multiple triangular systems</p>
<div class="sourceCode" id="cb146"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb146-1"><a href="#cb146-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb146-2"><a href="#cb146-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb146-3"><a href="#cb146-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb146-4"><a href="#cb146-4" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat,</span>
<span id="cb146-5"><a href="#cb146-5" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb146-6"><a href="#cb146-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb146-7"><a href="#cb146-7" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb146-8"><a href="#cb146-8" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb146-9"><a href="#cb146-9" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb146-10"><a href="#cb146-10" aria-hidden="true" tabindex="-1"></a>  InOutMat B,</span>
<span id="cb146-11"><a href="#cb146-11" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;</span>
<span id="cb146-12"><a href="#cb146-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb146-13"><a href="#cb146-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb146-14"><a href="#cb146-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb146-15"><a href="#cb146-15" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb146-16"><a href="#cb146-16" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat,</span>
<span id="cb146-17"><a href="#cb146-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> BinaryDivideOp<span class="op">&gt;</span></span>
<span id="cb146-18"><a href="#cb146-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb146-19"><a href="#cb146-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb146-20"><a href="#cb146-20" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb146-21"><a href="#cb146-21" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb146-22"><a href="#cb146-22" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb146-23"><a href="#cb146-23" aria-hidden="true" tabindex="-1"></a>  InOutMat B,</span>
<span id="cb146-24"><a href="#cb146-24" aria-hidden="true" tabindex="-1"></a>  BinaryDivideOp divide<span class="op">)</span>;  </span>
<span id="cb146-25"><a href="#cb146-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb146-26"><a href="#cb146-26" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb146-27"><a href="#cb146-27" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb146-28"><a href="#cb146-28" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb146-29"><a href="#cb146-29" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb146-30"><a href="#cb146-30" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb146-31"><a href="#cb146-31" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb146-32"><a href="#cb146-32" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb146-33"><a href="#cb146-33" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb146-34"><a href="#cb146-34" aria-hidden="true" tabindex="-1"></a>  InOutMat B<span class="op">)</span>;</span>
<span id="cb146-35"><a href="#cb146-35" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy,</span>
<span id="cb146-36"><a href="#cb146-36" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb146-37"><a href="#cb146-37" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb146-38"><a href="#cb146-38" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> DiagonalStorage,</span>
<span id="cb146-39"><a href="#cb146-39" aria-hidden="true" tabindex="-1"></a>         <em>inout-matrix</em> InOutMat<span class="op">&gt;</span></span>
<span id="cb146-40"><a href="#cb146-40" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> triangular_matrix_matrix_right_solve<span class="op">(</span></span>
<span id="cb146-41"><a href="#cb146-41" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb146-42"><a href="#cb146-42" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb146-43"><a href="#cb146-43" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb146-44"><a href="#cb146-44" aria-hidden="true" tabindex="-1"></a>  DiagonalStorage d,</span>
<span id="cb146-45"><a href="#cb146-45" aria-hidden="true" tabindex="-1"></a>  InOutMat B<span class="op">)</span>;</span></code></pre></div>
<p><i>[Note:</i> This algorithm makes it possible to compute
factorizations like Cholesky and LU in place.</p>
<p>Performing triangular solve in place hinders parallelization.
However, other <code>ExecutionPolicy</code>-specific optimizations, such
as vectorization, are still possible. This is why the
<code>ExecutionPolicy</code> overload exists. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Preconditions:</em> <code>A.extent(1)</code> equals
<code>B.extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Mandates:</em> If neither <code>A.static_extent(1)</code> nor
<code>B.static_extent(1)</code> equals <code>dynamic_extent</code>, then
<code>A.static_extent(1)</code> equals
<code>B.static_extent(1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Effects:</em> Overwrites <span class="math inline"><em>B</em></span>
with <span class="math inline"><em>X</em></span> such that <span class="math inline"><em>X</em><em>A</em> = <em>B</em></span>. If no such
<span class="math inline"><em>X</em></span> exists, then the elements of
<span class="math inline"><em>X</em></span> are valid but
unspecified.</p>
<p><i>[Note:</i> Since the triangular matrix is on the right, the
desired <code>divide</code> implementation in the case of noncommutative
multiplication would be mathematically equivalent to the product of the
first argument, and (the inverse of the second argument), in that order.
<i>– end note]</i></p>
<h1 data-number="17" id="examples"><span class="header-section-number">17</span> Examples<a href="#examples" class="self-link"></a></h1>
<h2 data-number="17.1" id="cholesky-factorization"><span class="header-section-number">17.1</span> Cholesky factorization<a href="#cholesky-factorization" class="self-link"></a></h2>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
This example shows how to compute the Cholesky factorization of a real
symmetric positive definite matrix <span class="math inline"><em>A</em></span> stored as an <code>mdspan</code>
with a unique non-packed layout. The algorithm imitates
<code>DPOTRF2</code> in LAPACK 3.9.0. If <code>Triangle</code> is
<code>upper_triangle_t</code>, then it computes the factorization <span class="math inline"><em>A</em> = <em>U</em><sup><em>T</em></sup><em>U</em></span>
in place, with U stored in the upper triangle of A on output. Otherwise,
it computes the factorization <span class="math inline"><em>A</em> = <em>L</em><em>L</em><sup><em>T</em></sup></span>
in place, with L stored in the lower triangle of A on output. The
function returns 0 if success, else k+1 if row/column k has a zero or
NaN (not a number) diagonal entry.</p>
<div class="sourceCode" id="cb147"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb147-1"><a href="#cb147-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;linalg&gt;</span></span>
<span id="cb147-2"><a href="#cb147-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;cmath&gt;</span></span>
<span id="cb147-3"><a href="#cb147-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb147-4"><a href="#cb147-4" aria-hidden="true" tabindex="-1"></a><span class="co">// Flip upper to lower, and lower to upper</span></span>
<span id="cb147-5"><a href="#cb147-5" aria-hidden="true" tabindex="-1"></a>lower_triangular_t opposite_triangle<span class="op">(</span>upper_triangular_t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb147-6"><a href="#cb147-6" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">{}</span></span>
<span id="cb147-7"><a href="#cb147-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb147-8"><a href="#cb147-8" aria-hidden="true" tabindex="-1"></a>upper_triangular_t opposite_triangle<span class="op">(</span>lower_triangular_t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb147-9"><a href="#cb147-9" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">{}</span></span>
<span id="cb147-10"><a href="#cb147-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb147-11"><a href="#cb147-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb147-12"><a href="#cb147-12" aria-hidden="true" tabindex="-1"></a><span class="co">// Returns nullopt if no bad pivots,</span></span>
<span id="cb147-13"><a href="#cb147-13" aria-hidden="true" tabindex="-1"></a><span class="co">// else the index of the first bad pivot.</span></span>
<span id="cb147-14"><a href="#cb147-14" aria-hidden="true" tabindex="-1"></a><span class="co">// A &quot;bad&quot; pivot is zero or NaN.</span></span>
<span id="cb147-15"><a href="#cb147-15" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>inout-matrix</em> InOutMat,</span>
<span id="cb147-16"><a href="#cb147-16" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb147-17"><a href="#cb147-17" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>optional<span class="op">&lt;</span><span class="kw">typename</span> InOutMat<span class="op">::</span>size_type<span class="op">&gt;</span></span>
<span id="cb147-18"><a href="#cb147-18" aria-hidden="true" tabindex="-1"></a>cholesky_factor<span class="op">(</span>InOutMat A, Triangle t<span class="op">)</span></span>
<span id="cb147-19"><a href="#cb147-19" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb147-20"><a href="#cb147-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> std<span class="op">::</span>submdspan;</span>
<span id="cb147-21"><a href="#cb147-21" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> std<span class="op">::</span>tuple;</span>
<span id="cb147-22"><a href="#cb147-22" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> value_type <span class="op">=</span> <span class="kw">typename</span> InOutMat<span class="op">::</span>value_type;</span>
<span id="cb147-23"><a href="#cb147-23" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> size_type <span class="op">=</span> <span class="kw">typename</span> InOutMat<span class="op">::</span>size_type;</span>
<span id="cb147-24"><a href="#cb147-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb147-25"><a href="#cb147-25" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> value_type ZERO <span class="op">{}</span>;</span>
<span id="cb147-26"><a href="#cb147-26" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> value_type ONE <span class="op">(</span><span class="fl">1.0</span><span class="op">)</span>;</span>
<span id="cb147-27"><a href="#cb147-27" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> size_type n <span class="op">=</span> A<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>;</span>
<span id="cb147-28"><a href="#cb147-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb147-29"><a href="#cb147-29" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>n <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb147-30"><a href="#cb147-30" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> std<span class="op">::</span>nullopt;</span>
<span id="cb147-31"><a href="#cb147-31" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb147-32"><a href="#cb147-32" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>n <span class="op">==</span> <span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb147-33"><a href="#cb147-33" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>A<span class="op">[</span><span class="dv">0</span>,<span class="dv">0</span><span class="op">]</span> <span class="op">&lt;=</span> ZERO <span class="op">||</span> std<span class="op">::</span>isnan<span class="op">(</span>A<span class="op">[</span><span class="dv">0</span>,<span class="dv">0</span><span class="op">]))</span> <span class="op">{</span></span>
<span id="cb147-34"><a href="#cb147-34" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="op">{</span>size_type<span class="op">(</span><span class="dv">1</span><span class="op">)}</span>;</span>
<span id="cb147-35"><a href="#cb147-35" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb147-36"><a href="#cb147-36" aria-hidden="true" tabindex="-1"></a>    A<span class="op">[</span><span class="dv">0</span>,<span class="dv">0</span><span class="op">]</span> <span class="op">=</span> std<span class="op">::</span>sqrt<span class="op">(</span>A<span class="op">[</span><span class="dv">0</span>,<span class="dv">0</span><span class="op">])</span>;</span>
<span id="cb147-37"><a href="#cb147-37" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb147-38"><a href="#cb147-38" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb147-39"><a href="#cb147-39" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Partition A into [A11, A12,</span></span>
<span id="cb147-40"><a href="#cb147-40" aria-hidden="true" tabindex="-1"></a>    <span class="co">//                   A21, A22],</span></span>
<span id="cb147-41"><a href="#cb147-41" aria-hidden="true" tabindex="-1"></a>    <span class="co">// where A21 is the transpose of A12.</span></span>
<span id="cb147-42"><a href="#cb147-42" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> size_type n1 <span class="op">=</span> n <span class="op">/</span> <span class="dv">2</span>;</span>
<span id="cb147-43"><a href="#cb147-43" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> size_type n2 <span class="op">=</span> n <span class="op">-</span> n1;</span>
<span id="cb147-44"><a href="#cb147-44" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> A11 <span class="op">=</span> submdspan<span class="op">(</span>A, pair<span class="op">{</span><span class="dv">0</span>, n1<span class="op">}</span>, pair<span class="op">{</span><span class="dv">0</span>, n1<span class="op">})</span>;</span>
<span id="cb147-45"><a href="#cb147-45" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> A22 <span class="op">=</span> submdspan<span class="op">(</span>A, pair<span class="op">{</span>n1, n<span class="op">}</span>, pair<span class="op">{</span>n1, n<span class="op">})</span>;</span>
<span id="cb147-46"><a href="#cb147-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb147-47"><a href="#cb147-47" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Factor A11</span></span>
<span id="cb147-48"><a href="#cb147-48" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> <span class="kw">auto</span> info1 <span class="op">=</span> cholesky_factor<span class="op">(</span>A11, t<span class="op">)</span>;</span>
<span id="cb147-49"><a href="#cb147-49" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>info1<span class="op">.</span>has_value<span class="op">())</span> <span class="op">{</span></span>
<span id="cb147-50"><a href="#cb147-50" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> info1;</span>
<span id="cb147-51"><a href="#cb147-51" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb147-52"><a href="#cb147-52" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb147-53"><a href="#cb147-53" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> std<span class="op">::</span>linalg<span class="op">::</span>explicit_diagonal;</span>
<span id="cb147-54"><a href="#cb147-54" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> std<span class="op">::</span>linalg<span class="op">::</span>symmetric_matrix_rank_k_update;</span>
<span id="cb147-55"><a href="#cb147-55" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> std<span class="op">::</span>linalg<span class="op">::</span>transposed;</span>
<span id="cb147-56"><a href="#cb147-56" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span>Triangle, upper_triangle_t<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb147-57"><a href="#cb147-57" aria-hidden="true" tabindex="-1"></a>      <span class="co">// Update and scale A12</span></span>
<span id="cb147-58"><a href="#cb147-58" aria-hidden="true" tabindex="-1"></a>      <span class="kw">auto</span> A12 <span class="op">=</span> submdspan<span class="op">(</span>A, tuple<span class="op">{</span><span class="dv">0</span>, n1<span class="op">}</span>, tuple<span class="op">{</span>n1, n<span class="op">})</span>;</span>
<span id="cb147-59"><a href="#cb147-59" aria-hidden="true" tabindex="-1"></a>      <span class="kw">using</span> std<span class="op">::</span>linalg<span class="op">::</span>triangular_matrix_matrix_left_solve;</span>
<span id="cb147-60"><a href="#cb147-60" aria-hidden="true" tabindex="-1"></a>      <span class="co">// BLAS would use original triangle; we need to flip it</span></span>
<span id="cb147-61"><a href="#cb147-61" aria-hidden="true" tabindex="-1"></a>      triangular_matrix_matrix_left_solve<span class="op">(</span>transposed<span class="op">(</span>A11<span class="op">)</span>,</span>
<span id="cb147-62"><a href="#cb147-62" aria-hidden="true" tabindex="-1"></a>        opposite_triangle<span class="op">(</span>t<span class="op">)</span>, explicit_diagonal, A12<span class="op">)</span>;</span>
<span id="cb147-63"><a href="#cb147-63" aria-hidden="true" tabindex="-1"></a>      <span class="co">// A22 = A22 - A12^T * A12</span></span>
<span id="cb147-64"><a href="#cb147-64" aria-hidden="true" tabindex="-1"></a>      <span class="co">//</span></span>
<span id="cb147-65"><a href="#cb147-65" aria-hidden="true" tabindex="-1"></a>      <span class="co">// The Triangle argument applies to A22,</span></span>
<span id="cb147-66"><a href="#cb147-66" aria-hidden="true" tabindex="-1"></a>      <span class="co">// not transposed(A12), so we don&#39;t flip it.</span></span>
<span id="cb147-67"><a href="#cb147-67" aria-hidden="true" tabindex="-1"></a>      symmetric_matrix_rank_k_update<span class="op">(-</span>ONE, transposed<span class="op">(</span>A12<span class="op">)</span>,</span>
<span id="cb147-68"><a href="#cb147-68" aria-hidden="true" tabindex="-1"></a>                                     A22, t<span class="op">)</span>;</span>
<span id="cb147-69"><a href="#cb147-69" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb147-70"><a href="#cb147-70" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb147-71"><a href="#cb147-71" aria-hidden="true" tabindex="-1"></a>      <span class="co">//</span></span>
<span id="cb147-72"><a href="#cb147-72" aria-hidden="true" tabindex="-1"></a>      <span class="co">// Compute the Cholesky factorization A = L * L^T</span></span>
<span id="cb147-73"><a href="#cb147-73" aria-hidden="true" tabindex="-1"></a>      <span class="co">//</span></span>
<span id="cb147-74"><a href="#cb147-74" aria-hidden="true" tabindex="-1"></a>      <span class="co">// Update and scale A21</span></span>
<span id="cb147-75"><a href="#cb147-75" aria-hidden="true" tabindex="-1"></a>      <span class="kw">auto</span> A21 <span class="op">=</span> submdspan<span class="op">(</span>A, tuple<span class="op">{</span>n1, n<span class="op">}</span>, tuple<span class="op">{</span><span class="dv">0</span>, n1<span class="op">})</span>;</span>
<span id="cb147-76"><a href="#cb147-76" aria-hidden="true" tabindex="-1"></a>      <span class="kw">using</span> std<span class="op">::</span>linalg<span class="op">::</span>triangular_matrix_matrix_right_solve;</span>
<span id="cb147-77"><a href="#cb147-77" aria-hidden="true" tabindex="-1"></a>      <span class="co">// BLAS would use original triangle; we need to flip it</span></span>
<span id="cb147-78"><a href="#cb147-78" aria-hidden="true" tabindex="-1"></a>      triangular_matrix_matrix_right_solve<span class="op">(</span>transposed<span class="op">(</span>A11<span class="op">)</span>,</span>
<span id="cb147-79"><a href="#cb147-79" aria-hidden="true" tabindex="-1"></a>        opposite_triangle<span class="op">(</span>t<span class="op">)</span>, explicit_diagonal, A21<span class="op">)</span>;</span>
<span id="cb147-80"><a href="#cb147-80" aria-hidden="true" tabindex="-1"></a>      <span class="co">// A22 = A22 - A21 * A21^T</span></span>
<span id="cb147-81"><a href="#cb147-81" aria-hidden="true" tabindex="-1"></a>      symmetric_matrix_rank_k_update<span class="op">(-</span>ONE, A21, A22, t<span class="op">)</span>;</span>
<span id="cb147-82"><a href="#cb147-82" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb147-83"><a href="#cb147-83" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb147-84"><a href="#cb147-84" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Factor A22</span></span>
<span id="cb147-85"><a href="#cb147-85" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> <span class="kw">auto</span> info2 <span class="op">=</span> cholesky_factor<span class="op">(</span>A22, t<span class="op">)</span>;</span>
<span id="cb147-86"><a href="#cb147-86" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>info2<span class="op">.</span>has_value<span class="op">())</span> <span class="op">{</span></span>
<span id="cb147-87"><a href="#cb147-87" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="op">{</span>info2<span class="op">.</span>value<span class="op">()</span> <span class="op">+</span> n1<span class="op">}</span>;</span>
<span id="cb147-88"><a href="#cb147-88" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb147-89"><a href="#cb147-89" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb147-90"><a href="#cb147-90" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb147-91"><a href="#cb147-91" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> std<span class="op">::</span>nullopt;</span>
<span id="cb147-92"><a href="#cb147-92" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="17.2" id="solve-linear-system-using-cholesky-factorization"><span class="header-section-number">17.2</span> Solve linear system using
Cholesky factorization<a href="#solve-linear-system-using-cholesky-factorization" class="self-link"></a></h2>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
This example shows how to solve a symmetric positive definite linear
system <span class="math inline"><em>A</em><em>x</em> = <em>b</em></span>, using the
Cholesky factorization computed in the previous example in-place in the
matrix <code>A</code>. The example assumes that
<code>cholesky_factor(A, t)</code> returned <code>nullopt</code>,
indicating no zero or NaN pivots.</p>
<div class="sourceCode" id="cb148"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb148-1"><a href="#cb148-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb148-2"><a href="#cb148-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle,</span>
<span id="cb148-3"><a href="#cb148-3" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec,</span>
<span id="cb148-4"><a href="#cb148-4" aria-hidden="true" tabindex="-1"></a>         <em>out-vector</em> OutVec<span class="op">&gt;</span></span>
<span id="cb148-5"><a href="#cb148-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> cholesky_solve<span class="op">(</span></span>
<span id="cb148-6"><a href="#cb148-6" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb148-7"><a href="#cb148-7" aria-hidden="true" tabindex="-1"></a>  Triangle t,</span>
<span id="cb148-8"><a href="#cb148-8" aria-hidden="true" tabindex="-1"></a>  InVec b,</span>
<span id="cb148-9"><a href="#cb148-9" aria-hidden="true" tabindex="-1"></a>  OutVec x<span class="op">)</span></span>
<span id="cb148-10"><a href="#cb148-10" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb148-11"><a href="#cb148-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> std<span class="op">::</span>linalg<span class="op">::</span>explicit_diagonal;</span>
<span id="cb148-12"><a href="#cb148-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> std<span class="op">::</span>linalg<span class="op">::</span>transposed;</span>
<span id="cb148-13"><a href="#cb148-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> std<span class="op">::</span>linalg<span class="op">::</span>triangular_matrix_vector_solve;</span>
<span id="cb148-14"><a href="#cb148-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb148-15"><a href="#cb148-15" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span>Triangle, upper_triangle_t<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb148-16"><a href="#cb148-16" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Solve Ax=b where A = U^T U</span></span>
<span id="cb148-17"><a href="#cb148-17" aria-hidden="true" tabindex="-1"></a>    <span class="co">//</span></span>
<span id="cb148-18"><a href="#cb148-18" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Solve U^T c = b, using x to store c.</span></span>
<span id="cb148-19"><a href="#cb148-19" aria-hidden="true" tabindex="-1"></a>    triangular_matrix_vector_solve<span class="op">(</span>transposed<span class="op">(</span>A<span class="op">)</span>,</span>
<span id="cb148-20"><a href="#cb148-20" aria-hidden="true" tabindex="-1"></a>      opposite_triangle<span class="op">(</span>t<span class="op">)</span>, explicit_diagonal, b, x<span class="op">)</span>;</span>
<span id="cb148-21"><a href="#cb148-21" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Solve U x = c, overwriting x with result.</span></span>
<span id="cb148-22"><a href="#cb148-22" aria-hidden="true" tabindex="-1"></a>    triangular_matrix_vector_solve<span class="op">(</span>A, t, explicit_diagonal, x<span class="op">)</span>;</span>
<span id="cb148-23"><a href="#cb148-23" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb148-24"><a href="#cb148-24" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb148-25"><a href="#cb148-25" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Solve Ax=b where A = L L^T</span></span>
<span id="cb148-26"><a href="#cb148-26" aria-hidden="true" tabindex="-1"></a>    <span class="co">//</span></span>
<span id="cb148-27"><a href="#cb148-27" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Solve L c = b, using x to store c.</span></span>
<span id="cb148-28"><a href="#cb148-28" aria-hidden="true" tabindex="-1"></a>    triangular_matrix_vector_solve<span class="op">(</span>A, t, explicit_diagonal, b, x<span class="op">)</span>;</span>
<span id="cb148-29"><a href="#cb148-29" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Solve L^T x = c, overwriting x with result.</span></span>
<span id="cb148-30"><a href="#cb148-30" aria-hidden="true" tabindex="-1"></a>    triangular_matrix_vector_solve<span class="op">(</span>transposed<span class="op">(</span>A<span class="op">)</span>,</span>
<span id="cb148-31"><a href="#cb148-31" aria-hidden="true" tabindex="-1"></a>      opposite_triangle<span class="op">(</span>t<span class="op">)</span>, explicit_diagonal, x<span class="op">)</span>;</span>
<span id="cb148-32"><a href="#cb148-32" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb148-33"><a href="#cb148-33" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="17.3" id="compute-qr-factorization-of-a-tall-skinny-matrix"><span class="header-section-number">17.3</span> Compute QR factorization of a
tall skinny matrix<a href="#compute-qr-factorization-of-a-tall-skinny-matrix" class="self-link"></a></h2>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
This example shows how to compute the QR factorization of a “tall and
skinny” matrix <code>V</code>, using a cache-blocked algorithm based on
rank-k symmetric matrix update and Cholesky factorization. “Tall and
skinny” means that the matrix has many more rows than columns.</p>
<div class="sourceCode" id="cb149"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb149-1"><a href="#cb149-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Compute QR factorization A = Q R, with A storing Q.</span></span>
<span id="cb149-2"><a href="#cb149-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>inout-matrix</em> InOutMat,</span>
<span id="cb149-3"><a href="#cb149-3" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb149-4"><a href="#cb149-4" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>optional<span class="op">&lt;</span><span class="kw">typename</span> InOutMat<span class="op">::</span>size_type<span class="op">&gt;</span></span>
<span id="cb149-5"><a href="#cb149-5" aria-hidden="true" tabindex="-1"></a>cholesky_tsqr_one_step<span class="op">(</span></span>
<span id="cb149-6"><a href="#cb149-6" aria-hidden="true" tabindex="-1"></a>  InOutMat A, <span class="co">// A on input, Q on output</span></span>
<span id="cb149-7"><a href="#cb149-7" aria-hidden="true" tabindex="-1"></a>  OutMat R<span class="op">)</span></span>
<span id="cb149-8"><a href="#cb149-8" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb149-9"><a href="#cb149-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> std<span class="op">::</span>full_extent;</span>
<span id="cb149-10"><a href="#cb149-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> std<span class="op">::</span>submdspan;</span>
<span id="cb149-11"><a href="#cb149-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> std<span class="op">::</span>tuple;</span>
<span id="cb149-12"><a href="#cb149-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> size_type <span class="op">=</span> <span class="kw">typename</span> InOutMat<span class="op">::</span>size_type;</span>
<span id="cb149-13"><a href="#cb149-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb149-14"><a href="#cb149-14" aria-hidden="true" tabindex="-1"></a>  <span class="co">// One might use cache size, sizeof(element_type), and A.extent(1)</span></span>
<span id="cb149-15"><a href="#cb149-15" aria-hidden="true" tabindex="-1"></a>  <span class="co">// to pick the number of rows per block.  For now, we just pick</span></span>
<span id="cb149-16"><a href="#cb149-16" aria-hidden="true" tabindex="-1"></a>  <span class="co">// some constant.</span></span>
<span id="cb149-17"><a href="#cb149-17" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> size_type max_num_rows_per_block <span class="op">=</span> <span class="dv">500</span>;</span>
<span id="cb149-18"><a href="#cb149-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb149-19"><a href="#cb149-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> R_value_type <span class="op">=</span> <span class="kw">typename</span> OutMat<span class="op">::</span>value_type;</span>
<span id="cb149-20"><a href="#cb149-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> R_element_type ZERO <span class="op">{}</span>;</span>
<span id="cb149-21"><a href="#cb149-21" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span>size_type j <span class="op">=</span> <span class="dv">0</span>; j <span class="op">&lt;</span> R<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>; <span class="op">++</span>j<span class="op">)</span> <span class="op">{</span></span>
<span id="cb149-22"><a href="#cb149-22" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span><span class="op">(</span>size_type i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> R<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb149-23"><a href="#cb149-23" aria-hidden="true" tabindex="-1"></a>      R<span class="op">[</span>i,j<span class="op">]</span> <span class="op">=</span> ZERO;</span>
<span id="cb149-24"><a href="#cb149-24" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb149-25"><a href="#cb149-25" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb149-26"><a href="#cb149-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb149-27"><a href="#cb149-27" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Cache-blocked version of R = R + A^T * A.</span></span>
<span id="cb149-28"><a href="#cb149-28" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="kw">auto</span> num_rows <span class="op">=</span> A<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>;</span>
<span id="cb149-29"><a href="#cb149-29" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> rest_num_rows <span class="op">=</span> num_rows;</span>
<span id="cb149-30"><a href="#cb149-30" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> A_rest <span class="op">=</span> A;</span>
<span id="cb149-31"><a href="#cb149-31" aria-hidden="true" tabindex="-1"></a>  <span class="cf">while</span><span class="op">(</span>A_rest<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">&gt;</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb149-32"><a href="#cb149-32" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> size_type num_rows_per_block <span class="op">=</span></span>
<span id="cb149-33"><a href="#cb149-33" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>min<span class="op">(</span>A<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>, max_num_rows_per_block<span class="op">)</span>;</span>
<span id="cb149-34"><a href="#cb149-34" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> A_cur <span class="op">=</span> submdspan<span class="op">(</span>A_rest,</span>
<span id="cb149-35"><a href="#cb149-35" aria-hidden="true" tabindex="-1"></a>      tuple<span class="op">{</span><span class="dv">0</span>, num_rows_per_block<span class="op">}</span>,</span>
<span id="cb149-36"><a href="#cb149-36" aria-hidden="true" tabindex="-1"></a>      full_extent<span class="op">)</span>;</span>
<span id="cb149-37"><a href="#cb149-37" aria-hidden="true" tabindex="-1"></a>    A_rest <span class="op">=</span> submdspan<span class="op">(</span>A_rest,</span>
<span id="cb149-38"><a href="#cb149-38" aria-hidden="true" tabindex="-1"></a>      tuple<span class="op">{</span>num_rows_per_block, A_rest<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)}</span>,</span>
<span id="cb149-39"><a href="#cb149-39" aria-hidden="true" tabindex="-1"></a>      full_extent<span class="op">)</span>;</span>
<span id="cb149-40"><a href="#cb149-40" aria-hidden="true" tabindex="-1"></a>    <span class="co">// R = R + A_cur^T * A_cur</span></span>
<span id="cb149-41"><a href="#cb149-41" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> std<span class="op">::</span>linalg<span class="op">::</span>symmetric_matrix_rank_k_update;</span>
<span id="cb149-42"><a href="#cb149-42" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> R_element_type ONE<span class="op">(</span><span class="fl">1.0</span><span class="op">)</span>;</span>
<span id="cb149-43"><a href="#cb149-43" aria-hidden="true" tabindex="-1"></a>    <span class="co">// The Triangle argument applies to R,</span></span>
<span id="cb149-44"><a href="#cb149-44" aria-hidden="true" tabindex="-1"></a>    <span class="co">// not transposed(A_cur), so we don&#39;t flip it.</span></span>
<span id="cb149-45"><a href="#cb149-45" aria-hidden="true" tabindex="-1"></a>    symmetric_matrix_rank_k_update<span class="op">(</span>ONE,</span>
<span id="cb149-46"><a href="#cb149-46" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>linalg<span class="op">::</span>transposed<span class="op">(</span>A_cur<span class="op">)</span>,</span>
<span id="cb149-47"><a href="#cb149-47" aria-hidden="true" tabindex="-1"></a>      R, upper_triangle<span class="op">)</span>;</span>
<span id="cb149-48"><a href="#cb149-48" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb149-49"><a href="#cb149-49" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb149-50"><a href="#cb149-50" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="kw">auto</span> info <span class="op">=</span> cholesky_factor<span class="op">(</span>R, upper_triangle<span class="op">)</span>;</span>
<span id="cb149-51"><a href="#cb149-51" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span><span class="op">(</span>info<span class="op">.</span>has_value<span class="op">())</span> <span class="op">{</span></span>
<span id="cb149-52"><a href="#cb149-52" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> info;</span>
<span id="cb149-53"><a href="#cb149-53" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb149-54"><a href="#cb149-54" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> std<span class="op">::</span>linalg<span class="op">::</span>triangular_matrix_matrix_left_solve;</span>
<span id="cb149-55"><a href="#cb149-55" aria-hidden="true" tabindex="-1"></a>  triangular_matrix_matrix_left_solve<span class="op">(</span>R, upper_triangle, A<span class="op">)</span>;</span>
<span id="cb149-56"><a href="#cb149-56" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> std<span class="op">::</span>nullopt;</span>
<span id="cb149-57"><a href="#cb149-57" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb149-58"><a href="#cb149-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb149-59"><a href="#cb149-59" aria-hidden="true" tabindex="-1"></a><span class="co">// Compute QR factorization A = Q R.</span></span>
<span id="cb149-60"><a href="#cb149-60" aria-hidden="true" tabindex="-1"></a><span class="co">// Use R_tmp as temporary R factor storage</span></span>
<span id="cb149-61"><a href="#cb149-61" aria-hidden="true" tabindex="-1"></a><span class="co">// for iterative refinement.</span></span>
<span id="cb149-62"><a href="#cb149-62" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb149-63"><a href="#cb149-63" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat1,</span>
<span id="cb149-64"><a href="#cb149-64" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat2,</span>
<span id="cb149-65"><a href="#cb149-65" aria-hidden="true" tabindex="-1"></a>         <em>out-matrix</em> OutMat3<span class="op">&gt;</span></span>
<span id="cb149-66"><a href="#cb149-66" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>optional<span class="op">&lt;</span><span class="kw">typename</span> OutMat1<span class="op">::</span>size_type<span class="op">&gt;</span></span>
<span id="cb149-67"><a href="#cb149-67" aria-hidden="true" tabindex="-1"></a>cholesky_tsqr<span class="op">(</span></span>
<span id="cb149-68"><a href="#cb149-68" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb149-69"><a href="#cb149-69" aria-hidden="true" tabindex="-1"></a>  OutMat1 Q,</span>
<span id="cb149-70"><a href="#cb149-70" aria-hidden="true" tabindex="-1"></a>  OutMat2 R_tmp,</span>
<span id="cb149-71"><a href="#cb149-71" aria-hidden="true" tabindex="-1"></a>  OutMat3 R<span class="op">)</span></span>
<span id="cb149-72"><a href="#cb149-72" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb149-73"><a href="#cb149-73" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>R<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> R<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb149-74"><a href="#cb149-74" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>A<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">==</span> R<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb149-75"><a href="#cb149-75" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>R_tmp<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> R_tmp<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb149-76"><a href="#cb149-76" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>A<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> Q<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb149-77"><a href="#cb149-77" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>A<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">==</span> Q<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb149-78"><a href="#cb149-78" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb149-79"><a href="#cb149-79" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>linalg<span class="op">::</span>copy<span class="op">(</span>A, Q<span class="op">)</span>;</span>
<span id="cb149-80"><a href="#cb149-80" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="kw">auto</span> info1 <span class="op">=</span> cholesky_tsqr_one_step<span class="op">(</span>Q, R<span class="op">)</span>;</span>
<span id="cb149-81"><a href="#cb149-81" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span><span class="op">(</span>info1<span class="op">.</span>has_value<span class="op">())</span> <span class="op">{</span></span>
<span id="cb149-82"><a href="#cb149-82" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> info1;</span>
<span id="cb149-83"><a href="#cb149-83" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb149-84"><a href="#cb149-84" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Use one step of iterative refinement to improve accuracy.</span></span>
<span id="cb149-85"><a href="#cb149-85" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="kw">auto</span> info2 <span class="op">=</span> cholesky_tsqr_one_step<span class="op">(</span>Q, R_tmp<span class="op">)</span>;</span>
<span id="cb149-86"><a href="#cb149-86" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span><span class="op">(</span>info2<span class="op">.</span>has_value<span class="op">())</span> <span class="op">{</span></span>
<span id="cb149-87"><a href="#cb149-87" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> info2;</span>
<span id="cb149-88"><a href="#cb149-88" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb149-89"><a href="#cb149-89" aria-hidden="true" tabindex="-1"></a>  <span class="co">// R = R_tmp * R</span></span>
<span id="cb149-90"><a href="#cb149-90" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> std<span class="op">::</span>linalg<span class="op">::</span>triangular_matrix_left_product;</span>
<span id="cb149-91"><a href="#cb149-91" aria-hidden="true" tabindex="-1"></a>  triangular_matrix_left_product<span class="op">(</span>R_tmp, upper_triangle,</span>
<span id="cb149-92"><a href="#cb149-92" aria-hidden="true" tabindex="-1"></a>                                 explicit_diagonal, R<span class="op">)</span>;</span>
<span id="cb149-93"><a href="#cb149-93" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> std<span class="op">::</span>nullopt;</span>
<span id="cb149-94"><a href="#cb149-94" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
</div>
</body>
</html>
