<!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="2024-09-11" />
  <title>Fix C++26 by making the rank-1, rank-2, rank-k, and rank-2k updates consistent with 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 { 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: #00AA00}
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">Fix C++26 by making the
rank-1, rank-2, rank-k, and rank-2k updates consistent with the
BLAS</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #: </td>
    <td>P3371R1</td>
  </tr>
  <tr>
    <td>Date: </td>
    <td>2024-09-11</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>
      Ilya Burylov<br>&lt;<a href="mailto:burylov@gmail.com" class="email">burylov@gmail.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" id="toc-authors"><span class="toc-section-number">1</span> Authors</a></li>
<li><a href="#revision-history" id="toc-revision-history"><span class="toc-section-number">2</span> Revision history</a></li>
<li><a href="#abstract" id="toc-abstract"><span class="toc-section-number">3</span> Abstract</a></li>
<li><a href="#discussion-and-proposed-changes" id="toc-discussion-and-proposed-changes"><span class="toc-section-number">4</span> Discussion and proposed changes</a>
<ul>
<li><a href="#support-both-overwriting-and-updating-rank-k-and-rank-2k-updates" id="toc-support-both-overwriting-and-updating-rank-k-and-rank-2k-updates"><span class="toc-section-number">4.1</span> Support both overwriting and
updating rank-k and rank-2k updates</a>
<ul>
<li><a href="#blas-supports-scaling-factor-beta-stdlinalg-currently-does-not" id="toc-blas-supports-scaling-factor-beta-stdlinalg-currently-does-not"><span class="toc-section-number">4.1.1</span> BLAS supports scaling factor
beta; std::linalg currently does not</a></li>
<li><a href="#make-these-functions-consistent-with-general-matrix-product" id="toc-make-these-functions-consistent-with-general-matrix-product"><span class="toc-section-number">4.1.2</span> Make these functions consistent
with general matrix product</a></li>
<li><a href="#fix-requires-changing-behavior-of-existing-overloads" id="toc-fix-requires-changing-behavior-of-existing-overloads"><span class="toc-section-number">4.1.3</span> Fix requires changing behavior
of existing overloads</a></li>
<li><a href="#add-new-updating-overloads-make-existing-ones-overwriting" id="toc-add-new-updating-overloads-make-existing-ones-overwriting"><span class="toc-section-number">4.1.4</span> Add new updating overloads; make
existing ones overwriting</a></li>
</ul></li>
<li><a href="#change-rank-1-and-rank-2-updates-to-be-consistent-with-rank-k-and-rank-2k" id="toc-change-rank-1-and-rank-2-updates-to-be-consistent-with-rank-k-and-rank-2k"><span class="toc-section-number">4.2</span> Change rank-1 and rank-2 updates
to be consistent with rank-k and rank-2k</a>
<ul>
<li><a href="#current-stdlinalg-behavior" id="toc-current-stdlinalg-behavior"><span class="toc-section-number">4.2.1</span> Current std::linalg
behavior</a></li>
<li><a href="#current-behavior-is-inconsistent-with-blas-standard-and-rank-k-and-rank-2k-updates" id="toc-current-behavior-is-inconsistent-with-blas-standard-and-rank-k-and-rank-2k-updates"><span class="toc-section-number">4.2.2</span> Current behavior is inconsistent
with BLAS Standard and rank-k and rank-2k updates</a></li>
<li><a href="#this-change-would-remove-a-special-case-in-stdlinalgs-design" id="toc-this-change-would-remove-a-special-case-in-stdlinalgs-design"><span class="toc-section-number">4.2.3</span> This change would remove a
special case in std::linalg’s design</a></li>
<li><a href="#exposition-only-concept-no-longer-needed" id="toc-exposition-only-concept-no-longer-needed"><span class="toc-section-number">4.2.4</span> Exposition-only concept no
longer needed</a></li>
</ul></li>
<li><a href="#constrain-alpha-in-hermitian-rank-1-and-rank-k-updates-to-be-noncomplex" id="toc-constrain-alpha-in-hermitian-rank-1-and-rank-k-updates-to-be-noncomplex"><span class="toc-section-number">4.3</span> Constrain alpha in Hermitian
rank-1 and rank-k updates to be noncomplex</a>
<ul>
<li><a href="#scaling-factor-alpha-needs-to-be-noncomplex-else-update-may-be-non-hermitian" id="toc-scaling-factor-alpha-needs-to-be-noncomplex-else-update-may-be-non-hermitian"><span class="toc-section-number">4.3.1</span> Scaling factor alpha needs to be
noncomplex, else update may be non-Hermitian</a></li>
<li><a href="#nothing-wrong-with-rank-2-or-rank-2k-updates" id="toc-nothing-wrong-with-rank-2-or-rank-2k-updates"><span class="toc-section-number">4.3.2</span> Nothing wrong with rank-2 or
rank-2k updates</a></li>
<li><a href="#nothing-wrong-with-scaling-factor-beta" id="toc-nothing-wrong-with-scaling-factor-beta"><span class="toc-section-number">4.3.3</span> Nothing wrong with scaling
factor beta</a></li>
<li><a href="#nothing-wrong-with-hermitian-matrix-vector-and-matrix-matrix-products" id="toc-nothing-wrong-with-hermitian-matrix-vector-and-matrix-matrix-products"><span class="toc-section-number">4.3.4</span> Nothing wrong with Hermitian
matrix-vector and matrix-matrix products</a></li>
<li><a href="#what-if-scalar-is-noncomplex-but-conj-is-adl-findable" id="toc-what-if-scalar-is-noncomplex-but-conj-is-adl-findable"><span class="toc-section-number">4.3.5</span> What if <code>Scalar</code> is
noncomplex but <code>conj</code> is ADL-findable?</a></li>
</ul></li>
<li><a href="#triangular-matrix-products-unit-diagonals-and-scaling-factors" id="toc-triangular-matrix-products-unit-diagonals-and-scaling-factors"><span class="toc-section-number">4.4</span> Triangular matrix products, unit
diagonals, and scaling factors</a>
<ul>
<li><a href="#blas-applies-alpha-after-unit-diagonal-linalg-applies-it-before" id="toc-blas-applies-alpha-after-unit-diagonal-linalg-applies-it-before"><span class="toc-section-number">4.4.1</span> BLAS applies alpha after unit
diagonal; linalg applies it before</a></li>
<li><a href="#triangular-solve-algorithms-not-affected" id="toc-triangular-solve-algorithms-not-affected"><span class="toc-section-number">4.4.2</span> Triangular solve algorithms not
affected</a></li>
<li><a href="#triangular-matrix-vector-product-work-around" id="toc-triangular-matrix-vector-product-work-around"><span class="toc-section-number">4.4.3</span> Triangular matrix-vector product
work-around</a></li>
<li><a href="#triangular-matrix-matrix-product-example" id="toc-triangular-matrix-matrix-product-example"><span class="toc-section-number">4.4.4</span> Triangular matrix-matrix product
example</a></li>
<li><a href="#lapack-never-calls-xtrmm-with-the-implicit-unit-diagonal-option-and-alpha-not-equal-to-one" id="toc-lapack-never-calls-xtrmm-with-the-implicit-unit-diagonal-option-and-alpha-not-equal-to-one"><span class="toc-section-number">4.4.5</span> LAPACK never calls
<code>xTRMM</code> with the implicit unit diagonal option and
<code>alpha</code> not equal to one</a></li>
<li><a href="#fixes-would-not-break-backwards-compatibility" id="toc-fixes-would-not-break-backwards-compatibility"><span class="toc-section-number">4.4.6</span> Fixes would not break backwards
compatibility</a></li>
</ul></li>
<li><a href="#triangular-solves-unit-diagonals-and-scaling-factors" id="toc-triangular-solves-unit-diagonals-and-scaling-factors"><span class="toc-section-number">4.5</span> Triangular solves, unit diagonals,
and scaling factors</a>
<ul>
<li><a href="#blas-applies-alpha-after-unit-diagonal-linalg-applies-it-before-1" id="toc-blas-applies-alpha-after-unit-diagonal-linalg-applies-it-before-1"><span class="toc-section-number">4.5.1</span> BLAS applies alpha after unit
diagonal; linalg applies it before</a></li>
<li><a href="#work-around-requires-changing-all-elements-of-the-matrix" id="toc-work-around-requires-changing-all-elements-of-the-matrix"><span class="toc-section-number">4.5.2</span> Work-around requires changing
all elements of the matrix</a></li>
<li><a href="#unsupported-case-occurs-in-lapack" id="toc-unsupported-case-occurs-in-lapack"><span class="toc-section-number">4.5.3</span> Unsupported case occurs in
LAPACK</a></li>
<li><a href="#fixes-would-not-break-backwards-compatibility-1" id="toc-fixes-would-not-break-backwards-compatibility-1"><span class="toc-section-number">4.5.4</span> Fixes would not break backwards
compatibility</a></li>
</ul></li>
</ul></li>
<li><a href="#ordering-with-respect-to-other-proposals-and-lwg-issues" id="toc-ordering-with-respect-to-other-proposals-and-lwg-issues"><span class="toc-section-number">5</span> Ordering with respect to other
proposals and LWG issues</a></li>
<li><a href="#acknowledgments" id="toc-acknowledgments"><span class="toc-section-number">6</span> Acknowledgments</a></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">7</span> Wording</a>
<ul>
<li><a href="#new-exposition-only-concepts-for-possibly-packed-input-and-output-matrices" id="toc-new-exposition-only-concepts-for-possibly-packed-input-and-output-matrices"><span class="toc-section-number">7.1</span> New exposition-only concepts for
possibly-packed input and output matrices</a></li>
<li><a href="#new-exposition-only-concept-for-noncomplex-numbers" id="toc-new-exposition-only-concept-for-noncomplex-numbers"><span class="toc-section-number">7.2</span> New exposition-only concept for
noncomplex numbers</a></li>
<li><a href="#rank-1-update-functions-in-synopsis" id="toc-rank-1-update-functions-in-synopsis"><span class="toc-section-number">7.3</span> Rank-1 update functions in
synopsis</a></li>
<li><a href="#rank-2-update-functions-in-synopsis" id="toc-rank-2-update-functions-in-synopsis"><span class="toc-section-number">7.4</span> Rank-2 update functions in
synopsis</a></li>
<li><a href="#rank-k-update-functions-in-synopsis" id="toc-rank-k-update-functions-in-synopsis"><span class="toc-section-number">7.5</span> Rank-k update functions in
synopsis</a></li>
<li><a href="#rank-2k-update-functions-in-synopsis" id="toc-rank-2k-update-functions-in-synopsis"><span class="toc-section-number">7.6</span> Rank-2k update functions in
synopsis</a></li>
<li><a href="#specification-of-nonsymmetric-rank-1-update-functions" id="toc-specification-of-nonsymmetric-rank-1-update-functions"><span class="toc-section-number">7.7</span> Specification of nonsymmetric
rank-1 update functions</a></li>
<li><a href="#specification-of-symmetric-and-hermitian-rank-1-update-functions" id="toc-specification-of-symmetric-and-hermitian-rank-1-update-functions"><span class="toc-section-number">7.8</span> Specification of symmetric and
Hermitian rank-1 update functions</a></li>
<li><a href="#specification-of-symmetric-and-hermitian-rank-2-update-functions" id="toc-specification-of-symmetric-and-hermitian-rank-2-update-functions"><span class="toc-section-number">7.9</span> Specification of symmetric and
Hermitian rank-2 update functions</a></li>
<li><a href="#specification-of-rank-k-update-functions" id="toc-specification-of-rank-k-update-functions"><span class="toc-section-number">7.10</span> Specification of rank-k update
functions</a></li>
<li><a href="#specification-of-rank-2k-update-functions" id="toc-specification-of-rank-2k-update-functions"><span class="toc-section-number">7.11</span> Specification of rank-2k update
functions</a></li>
</ul></li>
</ul>
</div>
<h1 data-number="1" id="authors"><span class="header-section-number">1</span> Authors<a href="#authors" class="self-link"></a></h1>
<ul>
<li>Mark Hoemmen (mhoemmen@nvidia.com) (NVIDIA)</li>
<li>Ilya Burylov (burylov@gmail.com) (NVIDIA)</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 to be submitted 2024-08-15</p></li>
<li><p>Revision 1 to be submitted 2024-09-15</p>
<ul>
<li><p>Main wording changes from R0:</p>
<ul>
<li><p>Instead of just changing the symmetric and Hermitian rank-k and
rank-2k updates to have both overwriting and updating overloads, change
<em>all</em> the update functions in this way: rank-1 (general,
symmetric, and Hermitian), rank-2, rank-k, and rank-2k</p></li>
<li><p>For all the new updating overloads, specify that <code>C</code>
(or <code>A</code>) may alias <code>E</code></p></li>
<li><p>For the new symmetric and Hermitian updating overloads, specify
that the functions access the new <code>E</code> parameter in the same
way (e.g., with respect to the lower or upper triangle) as the
<code>C</code> (or <code>A</code>) parameter</p></li>
<li><p>Add exposition-only concept <em><code>noncomplex</code></em> to
constrain a scaling factor to be noncomplex, as needed for Hermitian
rank-1 and rank-k functions</p></li>
</ul></li>
<li><p>Add Ilya Burylov as coauthor</p></li>
<li><p>Change title and abstract to express the wording changes</p></li>
<li><p>Add nonwording section explaining why we change rank-1 and rank-2
updates to be consistent with rank-k and rank-2k updates</p></li>
<li><p>Add nonwording sections explaining why we don’t change
<code>hermitian_matrix_vector_product</code>,
<code>hermitian_matrix_product</code>,
<code>triangular_matrix_product</code>, or the triangular
solves</p></li>
<li><p>Add nonwording section explaining why we constrain some scaling
factors to be noncomplex at compile time, instead of taking a run-time
approach</p></li>
<li><p>Reorganize and expand nonwording sections</p></li>
</ul></li>
</ul>
<h1 data-number="3" id="abstract"><span class="header-section-number">3</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>The [linalg] functions <code>matrix_rank_1_update</code>,
<code>matrix_rank_1_update_c</code>,
<code>symmetric_rank_1_update</code>,
<code>hermitian_rank_1_update</code>,
<code>symmetric_matrix_rank_k_update</code>,
<code>hermitian_matrix_rank_k_update</code>,
<code>symmetric_matrix_rank_2k_update</code>, and
<code>hermitian_matrix_rank_2k_update</code> currently have behavior
inconsistent with their corresponding BLAS (Basic Linear Algebra
Subroutines) routines. Also, the behavior of the rank-k and rank-2k
updates is inconsistent with that of <code>matrix_product</code>, even
though in mathematical terms they are special cases of a matrix-matrix
product. We propose three fixes.</p>
<ol type="1">
<li><p>Add “updating” overloads to the rank-1, rank-2, rank-k, and
rank-2k update functions. The new overloads are analogous to the
updating overloads of <code>matrix_product</code>. For example,
<code>symmetric_matrix_rank_k_update(A, scaled(beta, C), C, upper_triangle)</code>
will perform <span class="math inline"><em>C</em> := <em>β</em><em>C</em> + <em>A</em><em>A</em><sup><em>T</em></sup></span>.</p></li>
<li><p>Change the behavior of the existing rank-1, rank-2, rank-k, and
rank-2k update functions to be “overwriting” instead of “unconditionally
updating.” For example,
<code>symmetric_matrix_rank_k_update(A, C, upper_triangle)</code> will
perform <span class="math inline"><em>C</em> = <em>A</em><em>A</em><sup><em>T</em></sup></span>
instead of <span class="math inline"><em>C</em> := <em>C</em> + <em>A</em><em>A</em><sup><em>T</em></sup></span>.</p></li>
<li><p>For <code>hermitian_rank_1_update</code> and
<code>hermitian_rank_k_update</code>, constrain the <code>Scalar</code>
template parameter (if any) to be noncomplex. This ensures that the
update will be mathematically Hermitian. (A constraint is not needed for
the rank-2 and rank-2k update functions.)</p></li>
</ol>
<p>Items (2) and (3) are breaking changes to the current Working Draft.
Thus, we must finish this before finalization of C++26.</p>
<h1 data-number="4" id="discussion-and-proposed-changes"><span class="header-section-number">4</span> Discussion and proposed changes<a href="#discussion-and-proposed-changes" class="self-link"></a></h1>
<h2 data-number="4.1" id="support-both-overwriting-and-updating-rank-k-and-rank-2k-updates"><span class="header-section-number">4.1</span> Support both overwriting and
updating rank-k and rank-2k updates<a href="#support-both-overwriting-and-updating-rank-k-and-rank-2k-updates" class="self-link"></a></h2>
<h3 data-number="4.1.1" id="blas-supports-scaling-factor-beta-stdlinalg-currently-does-not"><span class="header-section-number">4.1.1</span> BLAS supports scaling factor
beta; std::linalg currently does not<a href="#blas-supports-scaling-factor-beta-stdlinalg-currently-does-not" class="self-link"></a></h3>
<p>Each function in any section whose label begins with “linalg.algs”
generally corresponds to one or more routines or functions in the
original BLAS (Basic Linear Algebra Subroutines). Every computation that
the BLAS can do, a function in the C++ Standard Library should be able
to do.</p>
<p>One <code>std::linalg</code> user
<a href="https://github.com/kokkos/stdBLAS/issues/272#issuecomment-2248273146">reported</a>
an exception to this rule. The BLAS routine <code>DSYRK</code>
(Double-precision SYmmetric Rank-K update) computes <span class="math inline"><em>C</em> := <em>β</em><em>C</em> + <em>α</em><em>A</em><em>A</em><sup><em>T</em></sup></span>,
but the corresponding <code>std::linalg</code> function
<code>symmetric_matrix_rank_k_update</code> only computes <span class="math inline"><em>C</em> := <em>C</em> + <em>α</em><em>A</em><em>A</em><sup><em>T</em></sup></span>.
That is, <code>std::linalg</code> currently has no way to express this
BLAS operation with a general <span class="math inline"><em>β</em></span> scaling factor. This issue applies
to all of the symmetric and Hermitian rank-k and rank-2k update
functions.</p>
<ul>
<li><code>symmetric_matrix_rank_k_update</code>: computes <span class="math inline"><em>C</em> := <em>C</em> + <em>α</em><em>A</em><em>A</em><sup><em>T</em></sup></span></li>
<li><code>hermitian_matrix_rank_k_update</code>: computes <span class="math inline"><em>C</em> := <em>C</em> + <em>α</em><em>A</em><em>A</em><sup><em>H</em></sup></span></li>
<li><code>symmetric_matrix_rank_2k_update</code>: computes <span class="math inline"><em>C</em> := <em>C</em> + <em>α</em><em>A</em><em>B</em><sup><em>H</em></sup> + <em>α</em><em>B</em><em>A</em><sup><em>H</em></sup></span></li>
<li><code>hermitian_matrix_rank_2k_update</code>: computes <span class="math inline"><em>C</em> := <em>C</em> + <em>α</em><em>A</em><em>B</em><sup><em>H</em></sup> + <em>ᾱ</em><em>B</em><em>A</em><sup><em>H</em></sup></span>,
where <span class="math inline"><em>ᾱ</em></span> denotes the complex
conjugate of <span class="math inline"><em>α</em></span></li>
</ul>
<h3 data-number="4.1.2" id="make-these-functions-consistent-with-general-matrix-product"><span class="header-section-number">4.1.2</span> Make these functions
consistent with general matrix product<a href="#make-these-functions-consistent-with-general-matrix-product" class="self-link"></a></h3>
<p>These functions implement special cases of matrix-matrix products.
The <code>matrix_product</code> function in <code>std::linalg</code>
implements the general case of matrix-matrix products. This function
corresponds to the BLAS’s <code>SGEMM</code>, <code>DGEMM</code>,
<code>CGEMM</code>, and <code>ZGEMM</code>, which compute <span class="math inline"><em>C</em> := <em>β</em><em>C</em> + <em>α</em><em>A</em><em>B</em></span>,
where <span class="math inline"><em>α</em></span> and <span class="math inline"><em>β</em></span> are scaling factors. The
<code>matrix_product</code> function has two kinds of overloads:</p>
<ol type="1">
<li><p><em>overwriting</em> (<span class="math inline"><em>C</em> = <em>A</em><em>B</em></span>)
and</p></li>
<li><p><em>updating</em> (<span class="math inline"><em>C</em> = <em>E</em> + <em>A</em><em>B</em></span>).</p></li>
</ol>
<p>The updating overloads handle the general <span class="math inline"><em>α</em></span> and <span class="math inline"><em>β</em></span> case by
<code>matrix_product(scaled(alpha, A), B, scaled(beta, C), C)</code>.
The specification explicitly permits the input
<code>scaled(beta, C)</code> to alias the output <code>C</code>
(<strong>[linalg.algs.blas3.gemm]</strong> 10: “<em>Remarks</em>:
<code>C</code> may alias <code>E</code>”). The <code>std::linalg</code>
library provides overwriting and updating overloads so that it can do
everything that the BLAS does, just in a more idiomatically C++ way.
Please see
<a href="https://isocpp.org/files/papers/P1673R13.html#function-argument-aliasing-and-zero-scalar-multipliers">P1673R13
Section 10.3</a> (“Function argument aliasing and zero scalar
multipliers”) for a more detailed explanation.</p>
<h3 data-number="4.1.3" id="fix-requires-changing-behavior-of-existing-overloads"><span class="header-section-number">4.1.3</span> Fix requires changing
behavior of existing overloads<a href="#fix-requires-changing-behavior-of-existing-overloads" class="self-link"></a></h3>
<p>The problem with the current symmetric and Hermitian rank-k and
rank-2k functions is that they have the same <em>calling syntax</em> as
the overwriting version of <code>matrix_product</code>, but
<em>semantics</em> that differ from both the overwriting and the
updating versions of <code>matrix_product</code>. For example,</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>hermitian_matrix_rank_k_update<span class="op">(</span>alpha, A, C<span class="op">)</span>;</span></code></pre></div>
<p>updates <span class="math inline"><em>C</em></span> with <span class="math inline"><em>C</em> + <em>α</em><em>A</em><em>A</em><sup><em>H</em></sup></span>,
but</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>matrix_product<span class="op">(</span>scaled<span class="op">(</span>alpha, A<span class="op">)</span>, conjugate_transposed<span class="op">(</span>A<span class="op">)</span>, C<span class="op">)</span>;</span></code></pre></div>
<p>overwrites <span class="math inline"><em>C</em></span> with <span class="math inline"><em>α</em><em>A</em><em>A</em><sup><em>H</em></sup></span>.
The current rank-k and rank-2k overloads are not overwriting, so we
can’t just fix this problem by introducing an “updating” overload for
each function.</p>
<p>Incidentally, the fact that these functions have “update” in their
name is not relevant, because that naming choice is original to the
BLAS. The BLAS calls its corresponding <code>xSYRK</code>,
<code>xHERK</code>, <code>xSYR2K</code>, and <code>xHER2K</code>
routines “{Symmetric, Hermitian} rank {one, two} update,” even though
setting <span class="math inline"><em>β</em> = 0</span> makes these
routines “overwriting” in the sense of <code>std::linalg</code>.</p>
<h3 data-number="4.1.4" id="add-new-updating-overloads-make-existing-ones-overwriting"><span class="header-section-number">4.1.4</span> Add new updating overloads;
make existing ones overwriting<a href="#add-new-updating-overloads-make-existing-ones-overwriting" class="self-link"></a></h3>
<p>We propose to fix this by making the functions work just like
<code>matrix_vector_product</code> or <code>matrix_product</code>. This
entails three changes.</p>
<ol type="1">
<li><p>Add two new exposition-only concepts
<em><code>possibly-packed-in-matrix</code></em> and
<em><code>possibly-packed-out-matrix</code></em> for constraining input
and output parameters of the changed or new symmetric and Hermitian
update functions.</p></li>
<li><p>Add “updating” overloads of the symmetric and Hermitian rank-k
and rank-2k update functions.</p>
<ol type="a">
<li><p>The updating overloads take a new input matrix parameter
<code>E</code>, analogous to the updating overloads of
<code>matrix_product</code>, and make <code>C</code> an output parameter
instead of an in/out parameter. For example,
<code>symmetric_matrix_rank_k_update(A, E, C, upper_triangle)</code>
computes <span class="math inline"><em>C</em> = <em>E</em> + <em>A</em><em>A</em><sup><em>T</em></sup></span>.</p></li>
<li><p>Explicitly permit <code>C</code> and <code>E</code> to alias,
thus permitting the desired case where <code>E</code> is
<code>scaled(beta, C)</code>.</p></li>
<li><p>The updating overloads take <code>E</code> as a
<em><code>possibly-packed-in-matrix</code></em>, and take <code>C</code>
as a <em><code>possibly-packed-out-matrix</code></em> (instead of a
<em><code>possibly-packed-inout-matrix</code></em>).</p></li>
<li><p><code>E</code> must be accessed as a symmetric or Hermitian
matrix (depending on the function name) and such accesses must use the
same triangle as <code>C</code>. (The existing [linalg.general] 4
wording for symmetric and Hermitian behavior does not cover
<code>E</code>.)</p></li>
</ol></li>
<li><p>Change the behavior of the existing symmetric and Hermitian
rank-k and rank-2k overloads to be overwriting instead of updating.</p>
<ol type="a">
<li><p>For example,
<code>symmetric_matrix_rank_k_update(A, C, upper_triangle)</code> will
compute <span class="math inline"><em>C</em> = <em>A</em><em>A</em><sup><em>T</em></sup></span>
instead of <span class="math inline"><em>C</em> := <em>C</em> + <em>A</em><em>A</em><sup><em>T</em></sup></span>.</p></li>
<li><p>Change <code>C</code> from a
<em><code>possibly-packed-inout-matrix</code></em> to a
<em><code>possibly-packed-out-matrix</code></em>.</p></li>
</ol></li>
</ol>
<p>Items (2) and (3) are breaking changes to the current Working Draft.
This needs to be so that we can provide the overwriting behavior <span class="math inline"><em>C</em> := <em>α</em><em>A</em><em>A</em><sup><em>T</em></sup></span>
or <span class="math inline"><em>C</em> := <em>α</em><em>A</em><em>A</em><sup><em>H</em></sup></span>
that the corresponding BLAS routines already provide. Thus, we must
finish this before finalization of C++26.</p>
<p>Both sets of overloads still only write to the specified triangle
(lower or upper) of the output matrix <code>C</code>. As a result, the
new updating overloads only read from that triangle of the input matrix
<code>E</code>. Therefore, even though <code>E</code> may be a different
matrix than <code>C</code>, the updating overloads do not need an
additional <code>Triangle t_E</code> parameter for <code>E</code>. The
<code>symmetric_*</code> functions interpret <code>E</code> as symmetric
in the same way that they interpret <code>C</code> as symmetric, and the
<code>hermitian_*</code> functions interpret <code>E</code> as Hermitian
in the same way that they interpret <code>C</code> as Hermitian.
Nevertheless, we do need new wording to explain how the functions may
interpret and access <code>E</code>.</p>
<h2 data-number="4.2" id="change-rank-1-and-rank-2-updates-to-be-consistent-with-rank-k-and-rank-2k"><span class="header-section-number">4.2</span> Change rank-1 and rank-2
updates to be consistent with rank-k and rank-2k<a href="#change-rank-1-and-rank-2-updates-to-be-consistent-with-rank-k-and-rank-2k" class="self-link"></a></h2>
<ol type="1">
<li><p>Rank-1 and rank-2 updates currently unconditionally update and do
not take a <span class="math inline"><em>β</em></span> scaling
factor.</p></li>
<li><p>We propose making all the rank-1 and rank-2 update functions
consistent with the proposed change to the rank-k and rank-2k updates.
This means both changing the meaning of the current overloads to be
overwriting, and adding new overloads that are updating. This includes
general (nonsymmetric), symmetric, and Hermitian rank-1 update
functions, as well as symmetric and Hermitian rank-2 update
functions.</p></li>
<li><p>As a result, the exposition-only concept
<em><code>possibly-packed-inout-matrix</code></em> is no longer needed.
We propose removing it.</p></li>
</ol>
<h3 data-number="4.2.1" id="current-stdlinalg-behavior"><span class="header-section-number">4.2.1</span> Current std::linalg
behavior<a href="#current-stdlinalg-behavior" class="self-link"></a></h3>
<p>The rank-k and rank-2k update functions have the following rank-1 and
rank-2 analogs, where <span class="math inline"><em>A</em></span>
denotes a symmetric or Hermitian matrix (depending on the function’s
name) and <span class="math inline"><em>x</em></span> and <span class="math inline"><em>y</em></span> denote vectors.</p>
<ul>
<li><code>symmetric_matrix_rank_1_update</code>: computes <span class="math inline"><em>A</em> := <em>A</em> + <em>α</em><em>x</em><em>x</em><sup><em>T</em></sup></span></li>
<li><code>hermetian_matrix_rank_1_update</code>: computes <span class="math inline"><em>A</em> := <em>A</em> + <em>α</em><em>x</em><em>x</em><sup><em>H</em></sup></span></li>
<li><code>symmetric_matrix_rank_2_update</code>: computes <span class="math inline"><em>A</em> := <em>A</em> + <em>α</em><em>x</em><em>y</em><sup><em>T</em></sup> + <em>α</em><em>y</em><em>x</em><sup><em>T</em></sup></span></li>
<li><code>hermitian_matrix_rank_2_update</code>: computes <span class="math inline"><em>A</em> := <em>A</em> + <em>α</em><em>x</em><em>y</em><sup><em>H</em></sup> + <em>ᾱ</em><em>x</em><em>y</em><sup><em>H</em></sup></span></li>
</ul>
<p>These functions <em>unconditionally</em> update the matrix <span class="math inline"><em>A</em></span>. They do not have an overwriting
option. In this, they follow the “general” (not necessarily symmetric or
Hermitian) rank-1 update functions.</p>
<ul>
<li><code>matrix_rank_1_update</code>: computes <span class="math inline"><em>A</em> := <em>A</em> + <em>x</em><em>y</em><sup><em>T</em></sup></span></li>
<li><code>matrix_rank_1_update_c</code>: computes <span class="math inline"><em>A</em> := <em>A</em> + <em>x</em><em>y</em><sup><em>H</em></sup></span></li>
</ul>
<h3 data-number="4.2.2" id="current-behavior-is-inconsistent-with-blas-standard-and-rank-k-and-rank-2k-updates"><span class="header-section-number">4.2.2</span> Current behavior is
inconsistent with BLAS Standard and rank-k and rank-2k updates<a href="#current-behavior-is-inconsistent-with-blas-standard-and-rank-k-and-rank-2k-updates" class="self-link"></a></h3>
<p>These six rank-1 and rank-2 update functions map to BLAS routines as
follows.</p>
<ul>
<li><code>matrix_rank_1_update</code>: <code>xGER</code></li>
<li><code>matrix_rank_1_update</code>: <code>xGERC</code></li>
<li><code>symmetric_matrix_rank_1_update</code>: <code>xSYR</code>,
<code>xSPR</code></li>
<li><code>hermitian_matrix_rank_1_update</code>: <code>xHER</code>,
<code>xHPR</code></li>
<li><code>hermitian_matrix_rank_1_update</code>: <code>xSYR2</code>,
<code>xSPR2</code></li>
<li><code>hermitian_matrix_rank_1_update</code>: <code>xHER2</code>,
<code>xHPR2</code></li>
</ul>
<p>The Reference BLAS and the BLAS Standard (see Chapter 2, pp. 64 - 68)
differ here. The Reference BLAS and the original 1988 BLAS 2 paper
specify all of the rank-1 and rank-2 update routines listed above as
unconditionally updating, and not taking a <span class="math inline"><em>β</em></span> scaling factor. However, the
(2002) BLAS Standard specifies all of these rank-1 and rank-2 update
functions as taking a <span class="math inline"><em>β</em></span>
scaling factor. We consider the latter to express our design intent. It
is also consistent with the corresponding rank-k and rank-2k update
functions in the BLAS, which all take a <span class="math inline"><em>β</em></span> scaling factor and thus can do
either overwriting (with zero <span class="math inline"><em>β</em></span>) or updating (with nonzero <span class="math inline"><em>β</em></span>). These routines include
<code>xSYRK</code>, <code>xHERK</code>, <code>xSYR2K</code>, and
<code>xHER2K</code>. One could also include the general matrix-matrix
product <code>xGEMM</code> among these, as <code>xGEMM</code> also takes
a <span class="math inline"><em>β</em></span> scaling factor.</p>
<h3 data-number="4.2.3" id="this-change-would-remove-a-special-case-in-stdlinalgs-design"><span class="header-section-number">4.2.3</span> This change would remove a
special case in std::linalg’s design<a href="#this-change-would-remove-a-special-case-in-stdlinalgs-design" class="self-link"></a></h3>
<p><a href="https://isocpp.org/files/papers/P1673R13.html#function-argument-aliasing-and-zero-scalar-multipliers">Section
10.3 of P1673R13</a> explains the three ways that the std::linalg design
translates Fortran <code>INTENT(INOUT)</code> arguments into a C++
idiom.</p>
<ol type="1">
<li><p>Provide in-place and not-in-place overloads for triangular solve
and triangular multiply.</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 beta 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>
<p>Our design goal was for functions with vector or matrix output to
imitate <code>std::transform</code> as much as possible. This favors Way
(3) as the default approach, which turns <code>INTENT(INOUT)</code>
arguments on the Fortran side into separate input and output parameters
on the C++ side. Way (2) is really an awkward special case. The BLAS
Standard effectively eliminates this special case on the Fortran side by
making the rank-1 and rank-2 updates work just like the rank-k and
rank-2k updates, with a <span class="math inline"><em>β</em></span>
scaling factor. This makes it natural to eliminate the Way (2) special
case on the C++ side as well.</p>
<h3 data-number="4.2.4" id="exposition-only-concept-no-longer-needed"><span class="header-section-number">4.2.4</span> Exposition-only concept no
longer needed<a href="#exposition-only-concept-no-longer-needed" class="self-link"></a></h3>
<p>These changes make the exposition-only concept
<em><code>possibly-packed-inout-matrix</code></em> superfluous. We
propose removing it.</p>
<p>Note that this would not eliminate all uses of the exposition-only
concept <em><code>inout-matrix</code></em>. The in-place triangular
matrix product functions <code>triangular_matrix_left_product</code> and
<code>triangular_matrix_right_product</code>, and the in-place
triangular linear system solve functions
<code>triangular_matrix_matrix_left_solve</code> and
<code>triangular_matrix_matrix_right_solve</code> would still use
<em><code>inout-matrix</code></em>.</p>
<h2 data-number="4.3" id="constrain-alpha-in-hermitian-rank-1-and-rank-k-updates-to-be-noncomplex"><span class="header-section-number">4.3</span> Constrain alpha in Hermitian
rank-1 and rank-k updates to be noncomplex<a href="#constrain-alpha-in-hermitian-rank-1-and-rank-k-updates-to-be-noncomplex" class="self-link"></a></h2>
<h3 data-number="4.3.1" id="scaling-factor-alpha-needs-to-be-noncomplex-else-update-may-be-non-hermitian"><span class="header-section-number">4.3.1</span> Scaling factor alpha needs to
be noncomplex, else update may be non-Hermitian<a href="#scaling-factor-alpha-needs-to-be-noncomplex-else-update-may-be-non-hermitian" class="self-link"></a></h3>
<p>The C++ Working Draft already has <code>Scalar alpha</code> overloads
of <code>hermitian_rank_k_update</code>. The <code>Scalar</code> type
currently can be complex. However, if <code>alpha</code> has nonzero
imaginary part, then <span class="math inline"><em>α</em><em>A</em><em>A</em><sup><em>H</em></sup></span>
may no longer be a Hermitian matrix, even though <span class="math inline"><em>A</em><em>A</em><sup><em>H</em></sup></span> is
mathematically always Hermitian. For example, if <span class="math inline"><em>A</em></span> is the identity matrix (with ones
on the diagonal and zeros elsewhere) and <span class="math inline"><em>α</em> = <em>i</em></span>, then <span class="math inline"><em>α</em><em>A</em><em>A</em><sup><em>H</em></sup></span>
is the diagonal matrix whose diagonal elements are all <span class="math inline"><em>i</em></span>. While that matrix is symmetric,
it is not Hermitian, because all elements on the diagonal of a Hermitian
matrix must have nonzero imaginary part. The rank-1 update function
<code>hermitian_rank_1_update</code> has the analogous issue.</p>
<p>The BLAS solves this problem by having the Hermitian rank-1 update
routines <code>xHER</code> and rank-k update routines <code>xHERK</code>
take the scaling factor <span class="math inline"><em>α</em></span> as a
noncomplex number. This suggests a fix: For all
<code>hermitian_rank_1_update</code> and
<code>hermitian_rank_k_update</code> overloads that take
<code>Scalar alpha</code>, constrain <code>Scalar</code> so that it is
noncomplex. We can avoid introducing new undefined behavior (or “valid
but unspecified” elements of the output matrix) by making “noncomplex” a
constraint on the <code>Scalar</code> type of <code>alpha</code>.
“Noncomplex” should follow the definition of “noncomplex” used by
<em><code>conj-if-needed</code></em>: either an arithmetic type, or
<code>conj(E)</code> is not ADL-findable for an expression
<code>E</code> of type <code>Scalar</code>.</p>
<h3 data-number="4.3.2" id="nothing-wrong-with-rank-2-or-rank-2k-updates"><span class="header-section-number">4.3.2</span> Nothing wrong with rank-2 or
rank-2k updates<a href="#nothing-wrong-with-rank-2-or-rank-2k-updates" class="self-link"></a></h3>
<p>This issue does <em>not</em> arise with the rank-2 or rank-2k
updates. In the BLAS, the rank-2 updates <code>xHER2</code> and the
rank-2k updates <code>xHER2K</code> all take <code>alpha</code> as a
complex number. The matrix <span class="math inline"><em>α</em><em>A</em><em>B</em><sup><em>H</em></sup> + <em>ᾱ</em><em>B</em><em>A</em><sup><em>H</em></sup></span>
is Hermitian by construction, so there’s no need to impose a
precondition on the value of <span class="math inline"><em>α</em></span>.</p>
<h3 data-number="4.3.3" id="nothing-wrong-with-scaling-factor-beta"><span class="header-section-number">4.3.3</span> Nothing wrong with scaling
factor beta<a href="#nothing-wrong-with-scaling-factor-beta" class="self-link"></a></h3>
<p>Both the current wording and the proposed changes to all these update
functions behave correctly with respect to <code>beta</code>.</p>
<p>For the new updating overloads of
<code>hermitian_rank_1_update</code> and
<code>hermitian_rank_k_update</code>, [linalg] expresses a
<code>beta</code> scaling factor by letting users supply
<code>scaled(beta, C)</code> as the argument for <code>E</code>. The
wording only requires that <code>E</code> be Hermitian. If
<code>E</code> is <code>scaled(beta, C)</code>, this concerns only the
product of <code>beta</code> and <code>C</code>. It would be incorrect
to constrain <code>beta</code> or <code>C</code> separately. For
example, if <span class="math inline"><em>β</em> =  − <em>i</em></span>
and <span class="math inline"><em>C</em></span> is the matrix whose
elements are all <span class="math inline"><em>i</em></span>, then <span class="math inline"><em>C</em></span> is not Hermitian but <span class="math inline"><em>β</em><em>C</em></span> (and therefore
<code>scaled(beta, C)</code>) is Hermitian.</p>
<p>This issue does <em>not</em> arise with the rank-2k updates. For
example, the BLAS routine <code>xHER2K</code> takes <code>beta</code> as
a real number. The previous paragraph’s reasoning for <code>beta</code>
applies here as well.</p>
<p>This issue also does not arise with the rank-2 updates. In the
Reference BLAS, the rank-2 update routines <code>xHER2</code> do not
have a way to supply <code>beta</code>, while in the BLAS Standard,
<code>xHER2</code> <em>does</em> take <code>beta</code>. The BLAS
Standard says that “<span class="math inline"><em>α</em></span> is a
complex scalar and and [sic] <span class="math inline"><em>β</em></span>
is a real scalar.” The Fortran 77 and C bindings specify the type of
<code>beta</code> as real (<code>&lt;rtype&gt;</code> resp.
<code>RSCALAR_IN</code>), but the Fortran 95 binding lists both
<code>alpha</code> and <code>beta</code> as
<code>COMPLEX(&lt;wp&gt;)</code>. The type of <code>beta</code> in the
Fortran 95 is likely a typo, considering the wording.</p>
<h3 data-number="4.3.4" id="nothing-wrong-with-hermitian-matrix-vector-and-matrix-matrix-products"><span class="header-section-number">4.3.4</span> Nothing wrong with Hermitian
matrix-vector and matrix-matrix products<a href="#nothing-wrong-with-hermitian-matrix-vector-and-matrix-matrix-products" class="self-link"></a></h3>
<p>In our view, the current behavior of
<code>hermitian_matrix_vector_product</code> and
<code>hermitian_matrix_product</code> is correct with respect to the
<code>alpha</code> scaling factor. These functions do not need extra
overloads that take <code>Scalar alpha</code>. Users who want to supply
<code>alpha</code> with nonzero imaginary part should <em>not</em> scale
the matrix <code>A</code> (as in <code>scaled(alpha, A)</code>).
Instead, they should scale the input vector <code>x</code>, as in the
following.</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">auto</span> alpha <span class="op">=</span> std<span class="op">::</span>complex<span class="op">{</span><span class="fl">0.0</span>, <span class="fl">1.0</span><span class="op">}</span>;</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>hermitian_matrix_vector_product<span class="op">(</span>A, upper_triangle, scaled<span class="op">(</span>alpha, x<span class="op">)</span>, y<span class="op">)</span>;</span></code></pre></div>
<h4 data-number="4.3.4.1" id="in-blas-matrix-is-hermitian-but-scaled-matrix-need-not-be"><span class="header-section-number">4.3.4.1</span> In BLAS, matrix is
Hermitian, but scaled matrix need not be<a href="#in-blas-matrix-is-hermitian-but-scaled-matrix-need-not-be" class="self-link"></a></h4>
<p>In Chapter 2 of the BLAS Standard, both <code>xHEMV</code> and
<code>xHEMM</code> take the scaling factors <span class="math inline"><em>α</em></span> and <span class="math inline"><em>β</em></span> as complex numbers
(<code>COMPLEX&lt;wp&gt;</code>, where <code>&lt;wp&gt;</code>
represents the current working precision). The BLAS permits
<code>xHEMV</code> or <code>xHEMM</code> to be called with
<code>alpha</code> whose imaginary part is nonzero. The matrix that the
BLAS assumes to be Hermitian is <span class="math inline"><em>A</em></span>, not <span class="math inline"><em>α</em><em>A</em></span>. Even if <span class="math inline"><em>A</em></span> is Hermitian, <span class="math inline"><em>α</em><em>A</em></span> might not necessarily be
Hermitian. For example, if <span class="math inline"><em>A</em></span>
is the identity matrix (diagonal all ones) and <span class="math inline"><em>α</em></span> is <span class="math inline"><em>i</em></span>, then <span class="math inline"><em>α</em><em>A</em></span> is not Hermitian but
skew-Hermitian.</p>
<p>The current [linalg] wording requires that the input matrix be
Hermitian. This excludes using <code>scaled(alpha, A)</code> as the
input matrix, where <code>alpha</code> has nonzero imaginary part. For
example, the following gives mathematically incorrect results.</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> alpha <span class="op">=</span> std<span class="op">::</span>complex<span class="op">{</span><span class="fl">0.0</span>, <span class="fl">1.0</span><span class="op">}</span>;</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>hermitian_matrix_vector_product<span class="op">(</span>scaled<span class="op">(</span>alpha, A<span class="op">)</span>, upper_triangle, x, y<span class="op">)</span>;</span></code></pre></div>
<p>Note that the behavior of this is still well defined, at least after
applying the fix proposed in LWG4136 for diagonal elements with nonzero
imaginary part. It does not violate a precondition. Therefore, the
Standard has no way to tell the user that they did something wrong.</p>
<h4 data-number="4.3.4.2" id="status-quo-permits-scaling-via-the-input-vector"><span class="header-section-number">4.3.4.2</span> Status quo permits scaling
via the input vector<a href="#status-quo-permits-scaling-via-the-input-vector" class="self-link"></a></h4>
<p>The current wording permits introducing the scaling factor
<code>alpha</code> through the input vector.</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">auto</span> alpha <span class="op">=</span> std<span class="op">::</span>complex<span class="op">{</span><span class="fl">0.0</span>, <span class="fl">1.0</span><span class="op">}</span>;</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>hermitian_matrix_vector_product<span class="op">(</span>A, upper_triangle, scaled<span class="op">(</span>alpha, x<span class="op">)</span>, y<span class="op">)</span>;</span></code></pre></div>
<p>This is fine as long as <span class="math inline"><em>α</em><em>A</em><em>x</em></span> equals <span class="math inline"><em>A</em><em>α</em><em>x</em></span>, that is, as
long as <span class="math inline"><em>α</em></span> commutes with the
elements of A. This issue would only be of concern if those
multiplications might be noncommutative. We’re already well outside the
world of “types that do ordinary arithmetic with
<code>std::complex</code>.” This scenario would only arise given a
user-defined complex type, like
<code>user_complex&lt;user_noncommutative&gt;</code> in the example
below, whose real parts have noncommutative multiplication.</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">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> user_complex <span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  user_complex<span class="op">(</span>T re, T im<span class="op">)</span> <span class="op">:</span> re_<span class="op">(</span>re<span class="op">)</span>, im_<span class="op">(</span>im<span class="op">)</span> <span class="op">{}</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>  <span class="co">// ... overloaded arithmetic operators ...</span></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="kw">friend</span> T real<span class="op">(</span>user_complex<span class="op">&lt;</span>T<span class="op">&gt;</span> z<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> z<span class="op">.</span>re_; <span class="op">}</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">friend</span> T imag<span class="op">(</span>user_complex<span class="op">&lt;</span>T<span class="op">&gt;</span> z<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> z<span class="op">.</span>im_; <span class="op">}</span> </span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">friend</span> user_complex<span class="op">&lt;</span>T<span class="op">&gt;</span> conj<span class="op">(</span>user_complex<span class="op">&lt;</span>T<span class="op">&gt;</span> z<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">{</span>real<span class="op">(</span>z<span class="op">)</span>, <span class="op">-</span>imag<span class="op">(</span>z<span class="op">)}</span>;</span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></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="kw">private</span><span class="op">:</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a>  T re_, im_;</span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> alpha <span class="op">=</span> user_complex<span class="op">&lt;</span>user_noncommutative<span class="op">&gt;{</span>something, something_else<span class="op">}</span>;</span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a>hermitian_matrix_vector_product<span class="op">(</span>N, upper_triangle, scaled<span class="op">(</span>alpha, x<span class="op">)</span>, y<span class="op">)</span>;</span></code></pre></div>
<p>The [linalg] library was designed to support element types with
noncommutative multiplication. On the other hand, generally, if we speak
of Hermitian matrices or even of inner products (which are used to
define Hermitian matrices), we’re working in a vector space. This means
that multiplication of the matrix’s elements is commutative. Anything
more general than that is far beyond what the BLAS can do. Thus, we
think restricting use of <code>alpha</code> with nonzero imaginary part
to <code>scaled(alpha, x)</code> is not so onerous.</p>
<h4 data-number="4.3.4.3" id="scaling-via-the-input-vector-is-weird-but-the-least-bad-choice"><span class="header-section-number">4.3.4.3</span> Scaling via the input
vector is weird, but the least bad choice<a href="#scaling-via-the-input-vector-is-weird-but-the-least-bad-choice" class="self-link"></a></h4>
<p>Many users may not like the status quo of needing to scale
<code>x</code> instead of <code>A</code>. First, it differs from the
BLAS, which puts <code>alpha</code> before <code>A</code> in its
<code>xHEMV</code> and <code>xHEMM</code> function arguments. Second,
users would get no compile-time feedback and likely no run-time feedback
if they scale <code>A</code> instead of <code>x</code>. Their code would
compile and produce correct results for almost all matrix-vector or
matrix-matrix products, <em>except</em> for the Hermitian case, and
<em>only</em> when the scaling factor has a nonzero imaginary part.
However, we still think the status quo is the least bad choice. We
explain why by discussing the following alternatives.</p>
<ol type="1">
<li><p>Treat <code>scaled(alpha, A)</code> as a special case: expect
<code>A</code> to be Hermitian and permit <code>alpha</code> to have
nonzero imaginary part</p></li>
<li><p>Forbid <code>scaled(alpha, A)</code> at compile time, so that
users must scale <code>x</code> instead</p></li>
<li><p>Add overloads that take <code>alpha</code>, analogous to the
rank-1 and rank-k update functions</p></li>
</ol>
<p>The first choice is mathematically incorrect, as we will explain
below. The second is not incorrect, but could only catch some errors.
The third is likewise not incorrect, but would add a lot of overloads
for an uncommon use case, and would still not prevent users from scaling
the matrix in mathematically incorrect ways.</p>
<h5 data-number="4.3.4.3.1" id="bad-choice-special-cases-for-scaling-the-matrix"><span class="header-section-number">4.3.4.3.1</span> Bad choice: Special cases
for scaling the matrix<a href="#bad-choice-special-cases-for-scaling-the-matrix" class="self-link"></a></h5>
<p>“Treat <code>scaled(alpha, A)</code> as a special case” actually
means three special cases, given some nested accessor type
<code>Acc</code> and a scaling factor <code>alpha</code> of type
<code>Scalar</code>.</p>
<ol type="a">
<li><p><code>scaled(alpha, A)</code>, whose accessor type is
<code>scaled_accessor&lt;Scalar, Acc&gt;</code></p></li>
<li><p><code>conjugated(scaled(alpha, A))</code>, whose accessor type is
<code>conjugated_accessor&lt;scaled_accessor&lt;Scalar, Acc&gt;&gt;</code></p></li>
<li><p><code>scaled(alpha, conjugated(A))</code>, whose accessor type is
<code>scaled_accessor&lt;Scalar, conjugated_accessor&lt;Acc&gt;&gt;</code></p></li>
</ol>
<p>One could replace <code>conjugated</code> with
<code>conjugate_transposed</code> (which we expect to be more common in
practice) without changing the accessor type.</p>
<p>This approach violates the fundamental [linalg] principle that “…
each <code>mdspan</code> parameter of a function behaves as itself and
is not otherwise ‘modified’ by other parameters” (Section 10.2.5,
P1673R13). The behavior of [linalg] is agnostic of specific accessor
types, even though implementations likely have optimizations for
specific accessor types. [linalg] takes this approach for consistency,
even where it results in different behavior from the BLAS (see Section
10.5.2 of P1673R13). The application of this principle here is “the
input parameter <code>A</code> is always Hermitian.”</p>
<p>In this case, the consistency matters for mathematical correctness.
What if <code>scaled(alpha, A)</code> is Hermitian, but <code>A</code>
itself is not? An example is <span class="math inline"><em>α</em> =  − <em>i</em></span> and <span class="math inline"><em>A</em></span> is the 2 x 2 matrix whose elements
are all <span class="math inline"><em>i</em></span>. If we treat
<code>scaled_accessor</code> as a special case, then
<code>hermitian_matrix_vector_product</code> will compute different
results.</p>
<p>Another problem is that users are permitted to define their own
accessor types, including nested accessors. Arbitrary user accessors
might have <code>scaled_accessor</code> somewhere in that nesting, or
they might have the <em>effect</em> of <code>scaled_accessor</code>
without being called that. Thus, we can’t detect all possible ways that
the matrix might be scaled.</p>
<h5 data-number="4.3.4.3.2" id="not-so-good-choice-forbid-scaling-the-matrix-at-compile-time"><span class="header-section-number">4.3.4.3.2</span> Not-so-good choice:
Forbid scaling the matrix at compile time<a href="#not-so-good-choice-forbid-scaling-the-matrix-at-compile-time" class="self-link"></a></h5>
<p>Hermitian matrix-matrix and matrix-vector product functions could
instead <em>forbid</em> scaling the matrix at compile time, at least for
the three accessor type cases listed in the previous option.</p>
<ol type="a">
<li><p><code>scaled_accessor&lt;Scalar, Acc&gt;</code></p></li>
<li><p><code>conjugated_accessor&lt;scaled_accessor&lt;Scalar, Acc&gt;&gt;</code></p></li>
<li><p><code>scaled_accessor&lt;Scalar, conjugated_accessor&lt;Acc&gt;&gt;</code></p></li>
</ol>
<p>Doing this would certainly encourage correct behavior for the most
common cases. However, as mentioned above, users are permitted to define
their own accessor types, including nested accessors. Thus, we can’t
detect all ways that an arbitrary, possibly user-defined accessor might
scale the matrix. Furthermore, scaling the matrix might still be
mathematically correct. A scaling factor with nonzero imaginary part
might even <em>make</em> the matrix Hermitian. Applying <span class="math inline"><em>i</em></span> as a scaling factor twice would
give a perfectly valid scaling factor of <span class="math inline"> − 1</span>.</p>
<h5 data-number="4.3.4.3.3" id="not-so-good-choice-add-alpha-overloads"><span class="header-section-number">4.3.4.3.3</span> Not-so-good choice: Add
alpha overloads<a href="#not-so-good-choice-add-alpha-overloads" class="self-link"></a></h5>
<p>One could imagine adding overloads that take <code>alpha</code>,
analogous to the rank-1 and rank-k update overloads that take
<code>alpha</code>. Users could then write</p>
<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>hermitian_matrix_vector_product<span class="op">(</span>alpha, A, upper_triangle, x, y<span class="op">)</span>;</span></code></pre></div>
<p>instead of</p>
<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>hermitian_matrix_vector_product<span class="op">(</span>A, upper_triangle, scaled<span class="op">(</span>alpha, x<span class="op">)</span>, y<span class="op">)</span>;</span></code></pre></div>
<p>We do not support this approach. First, it would introduce many
overloads, without adding to what the existing overloads can accomplish.
(Users can already introduce the scaling factor <code>alpha</code>
through <code>x</code>.) Contrast this with the rank-1 and rank-k
Hermitian update functions, where not having <code>alpha</code>
overloads might break simple cases. Here are two examples.</p>
<ol type="1">
<li><p>If the matrix and vector element types and the scaling factor
<span class="math inline"><em>α</em> = 2</span> are all integers, then
the update <span class="math inline"><em>C</em> := <em>C</em> − 2<em>x</em><em>x</em><sup><em>H</em></sup></span>
can be computed using integer types and arithmetic with an
<code>alpha</code> overload. However, without an <code>alpha</code>
overload, the user would need to use <code>scaled(sqrt(2), x)</code> as
the input vector, thus forcing use of floating-point arithmetic that may
give inexact results.</p></li>
<li><p>The update <span class="math inline"><em>C</em> := <em>C</em> − <em>x</em><em>x</em><sup><em>H</em></sup></span>
would require resorting to complex arithmetic, as the only way to
express <span class="math inline"> − <em>x</em><em>x</em><sup><em>H</em></sup></span>
with the same scaling factor for both vectors is <span class="math inline">(<em>i</em><em>x</em>)(<em>i</em><em>x</em>)<sup><em>H</em></sup></span>.</p></li>
</ol>
<p>Second, <code>alpha</code> overloads would not prevent users from
<em>also</em> supplying <code>scaled(gamma, A)</code> as the matrix for
some other scaling factor <code>gamma</code>. Thus, instead of solving
the problem, the overloads would introduce more possibilities for
errors.</p>
<h3 data-number="4.3.5" id="what-if-scalar-is-noncomplex-but-conj-is-adl-findable"><span class="header-section-number">4.3.5</span> What if <code>Scalar</code>
is noncomplex but <code>conj</code> is ADL-findable?<a href="#what-if-scalar-is-noncomplex-but-conj-is-adl-findable" class="self-link"></a></h3>
<p>Our proposed change defines a “noncomplex number” at compile time. We
say that complex numbers have <code>conj</code> that is findable by ADL,
and noncomplex numbers are either arithmetic types or do not have an
ADL-findable <code>conj</code>. We choose this definition because it is
the same one that we use to define the behavior of
<code>conjugated_accessor</code> (and also <code>conjugated</code>, if
P3050 is adopted). It also is the C++ analog of what the BLAS does,
namely specify the type of the <code>alpha</code> argument as real
instead of complex.</p>
<p>This definition is conservative, because it excludes complex numbers
with zero imaginary part. For <code>conjugated_accessor</code> and
<code>conjugated</code>, this does not matter; the class and function
behave the same from the user’s perspective. The exposition-only
function <em><code>conj-if-needed</code></em> specifically exists so
that <code>conjugated_accessor</code> and <code>conjugated</code> do not
change their input <code>mdspan</code>’s <code>value_type</code>.
However, for the rank-1 and rank-k Hermitian update functions affected
by this proposal, constraining <code>Scalar alpha</code> at compile time
to be noncomplex prevents users from calling those functions with a
“complex” number <code>alpha</code> whose imaginary part is zero.</p>
<p>This matters if the user defines a number type <code>Real</code> that
is meant to represent noncomplex numbers, but nevertheless has an
ADL-findable <code>conj</code>, thus making it a “complex” number type
from the perspective of [linalg] functions. There are two ways users
might define <code>conj(Real)</code>.</p>
<ol type="1">
<li><p><em>Imitating</em> <code>std::complex</code>: Users might define
a complex number type <code>UserComplex</code> whose real and imaginary
parts have type <code>Real</code>, and then imitate the behavior of
<code>std::conj(double)</code> by defining
<code>UserComplex conj(Real x)</code> to return a
<code>UserComplex</code> number with real part <code>x</code> and
imaginary part zero.</p></li>
<li><p><em>Type-preserving</em>: <code>Real conj(Real x)</code> returns
<code>x</code>.</p></li>
</ol>
<p>Option (1) would be an unfortunate choice. [linalg] defines
<em><code>conj-if-needed</code></em> specifically to fix the problem
that <code>std::conj(double)</code> returns
<code>std::complex&lt;double&gt;</code> instead of <code>double</code>.
However, Option (2) would be a reasonable thing for users to do,
especially if they have designed custom number types without [linalg] in
mind. One could accommodate such users by relaxing the constraint on
<code>Scalar</code> and taking one of the following two approaches.</p>
<ol type="1">
<li><p>Adding a precondition that
<em><code>imag-if-needed</code></em><code>(alpha)</code> equals
<code>Scalar{}</code></p></li>
<li><p>Imitating <a href="https://cplusplus.github.io/LWG/issue4136">LWG
4136</a>, by defining the scaling factor to be
<em><code>real-if-needed</code></em><code>(alpha)</code> instead of
<code>alpha</code></p></li>
</ol>
<p>We did not take Approach (1), because adding a precondition decreases
safety by adding undefined behavior. It also forces users to add
run-time checks. Defining those checks correctly for generic, possibly
but not necessarily complex number types would be challenging. We did
not take Approach (2) because its behavior would deviate from the BLAS,
which requires the scaling factor <code>alpha</code> to be noncomplex at
compile time.</p>
<h2 data-number="4.4" id="triangular-matrix-products-unit-diagonals-and-scaling-factors"><span class="header-section-number">4.4</span> Triangular matrix products,
unit diagonals, and scaling factors<a href="#triangular-matrix-products-unit-diagonals-and-scaling-factors" class="self-link"></a></h2>
<ol type="1">
<li><p>In BLAS, triangular matrix-vector and matrix-matrix products
apply <code>alpha</code> scaling to the implicit unit diagonal. In
[linalg], the scaling factor <code>alpha</code> is not applied to the
implicit unit diagonal. This is because the library does not interpret
<code>scaled(alpha, A)</code> differently than any other
<code>mdspan</code>.</p></li>
<li><p>Users of triangular matrix-vector products can recover BLAS
functionality by scaling the input vector instead of the input matrix,
so this only matters for triangular matrix-matrix products.</p></li>
<li><p>All calls of the BLAS’s triangular matrix-matrix product routine
<code>xTRMM</code> in LAPACK (other than in testing routines) use
<code>alpha</code> equal to one.</p></li>
<li><p>Straightforward approaches for fixing this issue would not break
backwards compatibility.</p></li>
<li><p>Therefore, we do not consider fixing this a high-priority issue,
and we do not propose a fix for it in this paper.</p></li>
</ol>
<h3 data-number="4.4.1" id="blas-applies-alpha-after-unit-diagonal-linalg-applies-it-before"><span class="header-section-number">4.4.1</span> BLAS applies alpha after unit
diagonal; linalg applies it before<a href="#blas-applies-alpha-after-unit-diagonal-linalg-applies-it-before" class="self-link"></a></h3>
<p>The <code>triangular_matrix_vector_product</code> and
<code>triangular_matrix_product</code> algorithms have an
<code>implicit_unit_diagonal</code> option. This makes the algorithm not
access the diagonal of the matrix, and compute as if the diagonal were
all ones. The option corresponds to the BLAS’s “Unit” flag. BLAS
routines that take both a “Unit” flag and an <code>alpha</code> scaling
factor apply “Unit” <em>before</em> scaling by <code>alpha</code>, so
that the matrix is treated as if it has a diagonal of all
<code>alpha</code> values. In contrast, [linalg] follows the general
principle that <code>scaled(alpha, A)</code> should be treated like any
other kind of <code>mdspan</code>. As a result, algorithms interpret
<code>implicit_unit_diagonal</code> as applied to the matrix
<em>after</em> scaling by <code>alpha</code>, so that the matrix still
has a diagonal of all ones.</p>
<h3 data-number="4.4.2" id="triangular-solve-algorithms-not-affected"><span class="header-section-number">4.4.2</span> Triangular solve algorithms
not affected<a href="#triangular-solve-algorithms-not-affected" class="self-link"></a></h3>
<p>The triangular solve algorithms in std::linalg are not affected,
because their BLAS analogs either do not take an <code>alpha</code>
argument (as with <code>xTRSV</code>), or the <code>alpha</code>
argument does not affect the triangular matrix (with <code>xTRSM</code>,
<code>alpha</code> affects the right-hand sides <code>B</code>, not the
triangular matrix <code>A</code>).</p>
<h3 data-number="4.4.3" id="triangular-matrix-vector-product-work-around"><span class="header-section-number">4.4.3</span> Triangular matrix-vector
product work-around<a href="#triangular-matrix-vector-product-work-around" class="self-link"></a></h3>
<p>This issue only reduces functionality of
<code>triangular_matrix_product</code>. Users of
<code>triangular_matrix_vector_product</code> who wish to replicate the
original BLAS functionality can scale the input matrix (by supplying
<code>scaled(alpha, x)</code> instead of <code>x</code> as the input
argument) instead of the triangular matrix.</p>
<h3 data-number="4.4.4" id="triangular-matrix-matrix-product-example"><span class="header-section-number">4.4.4</span> Triangular matrix-matrix
product example<a href="#triangular-matrix-matrix-product-example" class="self-link"></a></h3>
<p>The following example computes <span class="math inline"><em>A</em> := 2<em>A</em><em>B</em></span> where
<span class="math inline"><em>A</em></span> is a lower triangular
matrix, but it makes the diagonal of <span class="math inline"><em>A</em></span> all ones on the input (right-hand)
side.</p>
<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>triangular_matrix_product<span class="op">(</span>scaled<span class="op">(</span><span class="fl">2.0</span>, A<span class="op">)</span>, lower_triangle, implicit_unit_diagonal, B, A<span class="op">)</span>;</span></code></pre></div>
<p>Contrast with the analogous BLAS routine <code>DTRMM</code>, which
has the effect of making the diagonal elements all <code>2.0</code>.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode fortran"><code class="sourceCode fortranfixed"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>dtrmm(<span class="st">&#39;Left side&#39;</span>, <span class="st">&#39;Lower triangular&#39;</span>, <span class="st">&#39;No transpose&#39;</span>, <span class="st">&#39;Unit diagonal&#39;</span>, <span class="co">m, n, 2.0, A, lda, B, ldb)</span></span></code></pre></div>
<p>If we want to use [linalg] to express what the BLAS call expresses,
we need to perform a separate scaling.</p>
<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>triangular_matrix_product<span class="op">(</span>A, lower_triangle, implicit_unit_diagonal, B, A<span class="op">)</span>;</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>scale<span class="op">(</span><span class="fl">2.0</span>, A<span class="op">)</span>;</span></code></pre></div>
<p>This is counterintuitive, and may also affect performance.
Performance of <code>scale</code> is typically bound by memory bandwidth
and/or latency, but if the work done by <code>scale</code> could be
fused with the work done by the <code>triangular_matrix_product</code>,
then <code>scale</code>’s memory operations could be “hidden” in the
cost of the matrix product.</p>
<h3 data-number="4.4.5" id="lapack-never-calls-xtrmm-with-the-implicit-unit-diagonal-option-and-alpha-not-equal-to-one"><span class="header-section-number">4.4.5</span> LAPACK never calls
<code>xTRMM</code> with the implicit unit diagonal option and
<code>alpha</code> not equal to one<a href="#lapack-never-calls-xtrmm-with-the-implicit-unit-diagonal-option-and-alpha-not-equal-to-one" class="self-link"></a></h3>
<p>How much might users care about this missing [linalg] feature?
P1673R13 explains that the BLAS was codesigned with LAPACK and that
every reference BLAS routine is used by some LAPACK routine. “The BLAS
does not aim to provide a complete set of mathematical operations. Every
function in the BLAS exists because some LINPACK or LAPACK algorithm
needs it” (Section 10.6.1). Therefore, to judge the urgency of adding
new functionality to [linalg], we can ask whether the functionality
would be needed by a C++ re-implementation of LAPACK. We think not much,
because the highest-priority target audience of the BLAS is LAPACK
developers, and LAPACK routines (other than testing routines) never use
a scaling factor alpha other than one.</p>
<p>We survey calls to <code>xTRMM</code> in the latest version of LAPACK
as of the publication date of R1 of this proposal, LAPACK 3.12.0. It
suffices to survey <code>DTRMM</code>, the double-precision real case,
since for all the routines of interest, the complex case follows the
same pattern. (We did survey <code>ZTRMM</code>, the double-precision
complex case, just in case.) LAPACK has 24 routines that call
<code>DTRMM</code> directly. They fall into five categories.</p>
<ol type="1">
<li><p>Test routines: <code>DCHK3</code>, <code>DCHKE</code>,
<code>DLARHS</code></p></li>
<li><p>Routines relating to QR factorization or using the result of a QR
factorization (especially with block Householder reflectors):
<code>DGELQT3</code>, <code>DLARFB</code>, <code>DGEQRT3</code>,
<code>DLARFB_GETT</code>, <code>DLARZB</code>,
<code>DORM22</code></p></li>
<li><p>Routines relating to computing an inverse of a triangular matrix
or of a matrix that has been factored into triangular matrices:
<code>DLAUUM</code>, <code>DTRITRI</code>, <code>DTFTRI</code>,
<code>DPFTRI</code></p></li>
<li><p>Routines relating to solving eigenvalue (or generalized
eigenvalue) problems: <code>DLAHR2</code>, <code>DSYGST</code>,
<code>DGEHRD</code>, <code>DSYGV</code>, <code>DSYGV_2STAGE</code>,
<code>DSYGVD</code>, <code>DSYGVX</code> (note that <code>DLAQR5</code>
depends on <code>DTRMM</code> via <code>EXTERNAL</code> declaration, but
doesn’t actually call it)</p></li>
<li><p>Routines relating to symmetric indefinite factorizations:
<code>DSYT01_AA</code>, <code>DSYTRI2X</code>,
<code>DSYTRI_3X</code></p></li>
</ol>
<p>The only routines that call <code>DTRMM</code> with
<code>alpha</code> equal to anything other than one or negative one are
the testing routines. Some calls in <code>DGELQT3</code> and
<code>DLARFB_GETT</code> use negative one, but these calls never specify
an implicit unit diagonal (they use the explicit diagonal option). The
only routine that might possibly call <code>DTRMM</code> with both
negative one as alpha and the implicit unit diagonal is
<code>DTFTRI</code>. (This routine “computes the inverse of a triangular
matrix A stored in RFP [Rectangular Full Packed] format.” RFP format was
introduced to LAPACK in the late 2000’s, well after the BLAS Standard
was published. See
<a href="http://www.netlib.org/lapack/lawnspdf/lawn199.pdf">LAPACK
Working Note 199</a>, which was published in 2008.) <code>DTFTRI</code>
passes its caller’s <code>diag</code> argument (which specifies either
implicit unit diagonal or explicit diagonal) to <code>DTRMM</code>. The
only two LAPACK routines that call <code>DTFTRI</code> are
<code>DERRRFP</code> (a testing routine) and <code>DPFTRI</code>.
<code>DPFTRI</code> only ever calls <code>DTFTRI</code> with
<code>diag</code> <em>not</em> specifying the implicit unit diagonal
option. Therefore, LAPACK never needs both <code>alpha</code> not equal
to one and the implicit unit diagonal option, so adding the ability to
“scale the implicit diagonal” in [linalg] is a low-priority feature.</p>
<h3 data-number="4.4.6" id="fixes-would-not-break-backwards-compatibility"><span class="header-section-number">4.4.6</span> Fixes would not break
backwards compatibility<a href="#fixes-would-not-break-backwards-compatibility" class="self-link"></a></h3>
<p>We can think of two ways to fix this issue. First, we could add an
<code>alpha</code> scaling parameter, analogous to the symmetric and
Hermitian rank-1 and rank-k update functions. Second, we could add a new
kind of <code>Diagonal</code> template parameter type that expresses a
“diagonal value.” For example, <code>implicit_diagonal_t{alpha}</code>
(or a function form, <code>implicit_diagonal(alpha)</code>) would tell
the algorithm not to access the diagonal elements, but instead to assume
that their value is <code>alpha</code>. Both of these solutions would
let users specify the diagonal’s scaling factor separately from the
scaling factor for the rest of the matrix. Those two scaling factors
could differ, which is new functionality not offered by the BLAS. More
importantly, both of these solutions could be added later, after C++26,
without breaking backwards compatibility.</p>
<h2 data-number="4.5" id="triangular-solves-unit-diagonals-and-scaling-factors"><span class="header-section-number">4.5</span> Triangular solves, unit
diagonals, and scaling factors<a href="#triangular-solves-unit-diagonals-and-scaling-factors" class="self-link"></a></h2>
<ol type="1">
<li><p>In BLAS, triangular solves with possibly multiple right-hand
sides (<code>xTRSM</code>) apply <code>alpha</code> scaling to the
implicit unit diagonal. In [linalg], the scaling factor
<code>alpha</code> is not applied to the implicit unit diagonal. This is
because the library does not interpret <code>scaled(alpha, A)</code>
differently than any other <code>mdspan</code>.</p></li>
<li><p>Users of triangular solves would need a separate
<code>scale</code> call to recover BLAS functionality.</p></li>
<li><p>LAPACK sometimes calls <code>xTRSM</code> with <code>alpha</code>
not equal to one.</p></li>
<li><p>Straightforward approaches for fixing this issue would not break
backwards compatibility.</p></li>
<li><p>Therefore, we do not consider fixing this a high-priority issue,
and we do not propose a fix for it in this paper.</p></li>
</ol>
<h3 data-number="4.5.1" id="blas-applies-alpha-after-unit-diagonal-linalg-applies-it-before-1"><span class="header-section-number">4.5.1</span> BLAS applies alpha after unit
diagonal; linalg applies it before<a href="#blas-applies-alpha-after-unit-diagonal-linalg-applies-it-before-1" class="self-link"></a></h3>
<p>Triangular solves have a similar issue to the one explained in the
previous section. The BLAS routine <code>xTRSM</code> applies
<code>alpha</code> “after” the implicit unit diagonal, while std::linalg
applies <code>alpha</code> “before.” (<code>xTRSV</code> does not take
an <code>alpha</code> scaling factor.) As a result, the BLAS solves with
a different matrix than std::linalg.</p>
<p>In mathematical terms, <code>xTRSM</code> solves the equation <span class="math inline"><em>α</em>(<em>A</em>+<em>I</em>)<em>X</em> = <em>B</em></span>
for <span class="math inline"><em>X</em></span>, where <span class="math inline"><em>A</em></span> is the user’s input matrix
(without implicit unit diagonal) and <span class="math inline"><em>I</em></span> is the identity matrix (with ones
on the diagonal and zeros everywhere else).
<code>triangular_matrix_matrix_left_solve</code> solves the equation
<span class="math inline">(<em>α</em><em>A</em>+<em>I</em>)<em>Y</em> = <em>B</em></span>
for <span class="math inline"><em>Y</em></span>. The two results <span class="math inline"><em>X</em></span> and <span class="math inline"><em>Y</em></span> are not equal in general.</p>
<h3 data-number="4.5.2" id="work-around-requires-changing-all-elements-of-the-matrix"><span class="header-section-number">4.5.2</span> Work-around requires changing
all elements of the matrix<a href="#work-around-requires-changing-all-elements-of-the-matrix" class="self-link"></a></h3>
<p>Users could work around this problem by first scaling the matrix
<span class="math inline"><em>A</em></span> by <span class="math inline"><em>α</em></span>, and then solving for <span class="math inline"><em>Y</em></span>. In the common case where the
“other triangle” of <span class="math inline"><em>A</em></span> holds
another triangular matrix, users could not call
<code>scale(alpha, A)</code>. They would instead need to iterate over
the elements of <span class="math inline"><em>A</em></span> manually.
Users might also need to “unscale” the matrix after the solve. Another
option would be to copy the matrix <span class="math inline"><em>A</em></span> before scaling.</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="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">0</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2" 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> i <span class="op">+</span> <span class="dv">1</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="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    A<span class="op">[</span>i, j<span class="op">]</span> <span class="op">*=</span> alpha;</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>triangular_matrix_matrix_left_solve<span class="op">(</span>A, lower_triangle, implicit_unit_diagonal, B, Y<span class="op">)</span>;</span>
<span id="cb12-7"><a href="#cb12-7" 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">0</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-8"><a href="#cb12-8" 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> i <span class="op">+</span> <span class="dv">1</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="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>    A<span class="op">[</span>i, j<span class="op">]</span> <span class="op">/=</span> alpha;</span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Users cannot solve this problem by scaling <span class="math inline"><em>B</em></span> (either with
<code>scaled(1.0 / alpha, B)</code> or with
<code>scale(1.0 / alpha, B)</code>). Transforming <span class="math inline"><em>X</em></span> into <span class="math inline"><em>Y</em></span> or vice versa is mathematically
nontrivial in general, and may introduce new failure conditions. This
issue occurs with both the in-place and out-of-place triangular
solves.</p>
<h3 data-number="4.5.3" id="unsupported-case-occurs-in-lapack"><span class="header-section-number">4.5.3</span> Unsupported case occurs in
LAPACK<a href="#unsupported-case-occurs-in-lapack" class="self-link"></a></h3>
<p>The common case in LAPACK is calling <code>xTRSM</code> with
<code>alpha</code> equal to one, but other values of <code>alpha</code>
occur. For example, <code>xTRTRI</code> calls <code>xTRSM</code> with
<code>alpha</code> equal to <span class="math inline"> − 1</span>. Thus,
we cannot dismiss this issue, as we could with <code>xTRMM</code>.</p>
<h3 data-number="4.5.4" id="fixes-would-not-break-backwards-compatibility-1"><span class="header-section-number">4.5.4</span> Fixes would not break
backwards compatibility<a href="#fixes-would-not-break-backwards-compatibility-1" class="self-link"></a></h3>
<p>As with triangular matrix products above, we can think of two ways to
fix this issue. First, we could add an <code>alpha</code> scaling
parameter, analogous to the symmetric and Hermitian rank-1 and rank-k
update functions. Second, we could add a new kind of
<code>Diagonal</code> template parameter type that expresses a “diagonal
value.” For example, <code>implicit_diagonal_t{alpha}</code> (or a
function form, <code>implicit_diagonal(alpha)</code>) would tell the
algorithm not to access the diagonal elements, but instead to assume
that their value is <code>alpha</code>. Both of these solutions would
let users specify the diagonal’s scaling factor separately from the
scaling factor for the rest of the matrix. Those two scaling factors
could differ, which is new functionality not offered by the BLAS. More
importantly, both of these solutions could be added later, after C++26,
without breaking backwards compatibility.</p>
<h1 data-number="5" id="ordering-with-respect-to-other-proposals-and-lwg-issues"><span class="header-section-number">5</span> Ordering with respect to other
proposals and LWG issues<a href="#ordering-with-respect-to-other-proposals-and-lwg-issues" class="self-link"></a></h1>
<p>We currently have two other <code>std::linalg</code> fix papers in
review.</p>
<ul>
<li><p>P3222: Fix C++26 by adding <code>transposed</code> special cases
for P2642 layouts (forwarded by LEWG to LWG on 2024-08-27 pending
electronic poll results)</p></li>
<li><p>P3050: “Fix C++26 by optimizing <code>linalg::conjugated</code>
for noncomplex value types” (forwarded by LEWG to LWG on 2024-09-03
pending electronic poll results)</p></li>
</ul>
<p>LEWG was aware of these two papers and this pending paper P3371 in
its 2024-09-03 review of P3050R2. All three of these papers increment
the value of the <code>__cpp_lib_linalg</code> macro. While this
technically causes a conflict between the papers, advice from LEWG on
2024-09-03 was not to introduce special wording changes to avoid this
conflict.</p>
<p>We also have two outstanding LWG issues.</p>
<ul>
<li><p><a href="https://cplusplus.github.io/LWG/lwg-active.html#4136">LWG4136</a>
specifies the behavior of Hermitian algorithms on diagonal matrix
elements with nonzero imaginary part. (As the BLAS Standard specifies
and the Reference BLAS implements, the Hermitian algorithms do not
access the imaginary parts of diagonal elements, and assume they are
zero.) In our view, P3371 does not conflict with LWG4136.</p></li>
<li><p><a href="https://cplusplus.github.io/LWG/lwg-active.html#4137">LWG4137</a>,
“Fix Mandates, Preconditions, and Complexity elements of [linalg]
algorithms,” affects several sections touched by this proposal,
including [linalg.algs.blas3.rankk] and [linalg.algs.blas3.rank2k]. We
consider P3371 rebased atop the wording changes proposed by LWG4137.
While the wording changes may conflict in a formal (“diff”) sense, it is
our view that they do not conflict in a mathematical or specification
sense.</p></li>
</ul>
<h1 data-number="6" id="acknowledgments"><span class="header-section-number">6</span> Acknowledgments<a href="#acknowledgments" class="self-link"></a></h1>
<p>Many thanks (with permission) to Raffaele Solcà (CSCS Swiss National
Supercomputing Centre, <code>raffaele.solca@cscs.ch</code>) for pointing
out some of the issues fixed by this paper, as well as the issues
leading to LWG4137.</p>
<h1 data-number="7" id="wording"><span class="header-section-number">7</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.</p>
<p>In <strong>[version.syn]</strong>, for the following definition,</p>
</blockquote>
<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="pp">#define __cpp_lib_linalg </span>YYYYMML<span class="pp"> </span><span class="co">// also in &lt;linalg&gt;</span></span></code></pre></div>
<blockquote>
<p>adjust the placeholder value <code>YYYYMML</code> as needed so as to
denote this proposal’s date of adoption.</p>
</blockquote>
<h2 data-number="7.1" id="new-exposition-only-concepts-for-possibly-packed-input-and-output-matrices"><span class="header-section-number">7.1</span> New exposition-only concepts
for possibly-packed input and output matrices<a href="#new-exposition-only-concepts-for-possibly-packed-input-and-output-matrices" class="self-link"></a></h2>
<blockquote>
<p>Add the following lines to the header <code>&lt;linalg&gt;</code>
synopsis <strong>[linalg.syn]</strong>, just after the declaration of
the exposition-only concept <em><code>inout-matrix</code></em> and
before the declaration of the exposition-only concept
<em><code>possibly-packed-inout-matrix</code></em>. <i>[Editorial
Note:</i> This addition is not shown in green, becuase the authors could
not convince Markdown to format the code correctly. <i>– end
note]</i></p>
</blockquote>
<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> T<span class="op">&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> <em>possibly-packed-in-matrix</em> <span class="op">=</span> <em>see below</em>;     <span class="co">// <em>exposition only</em></span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-4"><a href="#cb14-4" 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="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> <em>possibly-packed-out-matrix</em> <span class="op">=</span> <em>see below</em>;     <span class="co">// <em>exposition only</em></span></span></code></pre></div>
<blockquote>
<p>Then, remove the declaration of the exposition-only concept
<em><code>possibly-packed-inout-matrix</code></em> from the header
<code>&lt;linalg&gt;</code> synopsis <strong>[linalg.syn]</strong>.</p>
</blockquote>
<blockquote>
<p>Then, add the following lines to
<strong>[linalg.helpers.concepts]</strong>, just after the definition of
the exposition-only variable template
<em><code>is-layout_blas_packed</code></em> and just before the
definition of the exposition-only concept
<em><code>possibly-packed-inout-matrix</code></em>. <i>[Editorial
Note:</i> This addition is not shown in green, becuase the authors could
not convince Markdown to format the code correctly. <i>– end
note]</i></p>
</blockquote>
<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> T<span class="op">&gt;</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> <em>possibly-packed-in-matrix</em> <span class="op">=</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>      <em>is-mdspan</em><span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> 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="cb15-4"><a href="#cb15-4" 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> <em>is-layout-blas-packed</em><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">::</span>layout_type<span class="op">&gt;)</span>;</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-6"><a href="#cb15-6" 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="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> <em>possibly-packed-out-matrix</em> <span class="op">=</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>      <em>is-mdspan</em><span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> 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="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a>      is_assignable_v<span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">::</span>reference, <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="cb15-10"><a href="#cb15-10" 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> <em>is-layout-blas-packed</em><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">::</span>layout_type<span class="op">&gt;)</span>;</span></code></pre></div>
<blockquote>
<p>Then, remove the definition of the exposition-only concept
<em><code>possibly-packed-inout-matrix</code></em> from
<strong>[linalg.helpers.concepts]</strong>.</p>
</blockquote>
<h2 data-number="7.2" id="new-exposition-only-concept-for-noncomplex-numbers"><span class="header-section-number">7.2</span> New exposition-only concept for
noncomplex numbers<a href="#new-exposition-only-concept-for-noncomplex-numbers" class="self-link"></a></h2>
<blockquote>
<p>In the Header <code>&lt;linalg&gt;</code> synopsis [linalg.syn], at
the end of the section started by the following comment:</p>
<p><code>// [linalg.helpers.concepts], linear algebra argument concepts</code>,</p>
<p>add the following declaration of the exposition-only concept
<em><code>noncomplex</code></em>. <i>[Editorial Note:</i> This addition
is not shown in green, becuase the authors could not convince Markdown
to format the code correctly. <i>– end note]</i></p>
</blockquote>
<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">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">concept</span> <em>noncomplex</em> <span class="op">=</span> <em>see below</em>; <span class="co">// exposition only</span></span></code></pre></div>
<blockquote>
<p>In [linalg.helpers.concepts], change paragraph 3 to read as follows
(new content in green).</p>
</blockquote>
<p>Unless explicitly permitted, any <em><code>inout-vector</code></em>,
<em><code>inout-matrix</code></em>, <em><code>inout-object</code></em>,
<em><code>out-vector</code></em>, <em><code>out-matrix</code></em>,
<em><code>out-object</code></em>, <span style="color: green;"><em><code>possibly-packed-out-matrix</code></em></span>,
or <em><code>possibly-packed-inout-matrix</code></em> parameter of a
function in [linalg] shall not overlap any other <code>mdspan</code>
parameter of the function.</p>
<blockquote>
<p>Append the following to the end of [linalg.helpers.concepts].
<i>[Editorial Note:</i> These additions are not shown in green, becuase
the authors could not convince Markdown to format the code correctly.
<i>– end note]</i></p>
</blockquote>
<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="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">concept</span> <em>noncomplex</em> <span class="op">=</span> <em>see below</em>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
A type <code>T</code> models <em><code>noncomplex</code></em> if
<code>T</code> is a linear algebra value type, and either</p>
<p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<code>T</code> is not an arithmetic type, or</p>
<p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> the
expression <code>conj(E)</code> is not 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>.</p>
<h2 data-number="7.3" id="rank-1-update-functions-in-synopsis"><span class="header-section-number">7.3</span> Rank-1 update functions in
synopsis<a href="#rank-1-update-functions-in-synopsis" class="self-link"></a></h2>
<blockquote>
<p>In the header <code>&lt;linalg&gt;</code> synopsis
<strong>[linalg.syn]</strong>, replace all the declarations of all the
<code>matrix_rank_1_update</code>, <code>matrix_rank_1_update_c</code>,
<code>symmetric_matrix_rank_1_update</code>, and
<code>hermitian_matrix_rank_1_update</code> overloads to read as
follows. <i>[Editorial Note:</i> There are three changes here. First,
the existing overloads become “overwriting” overloads. Second, new
“updating” overloads are added. Third, the
<code>hermitian_rank_1_update</code> functions that take an
<code>alpha</code> parameter now constrain <code>alpha</code> to be
<em><code>noncomplex</code></em>.</p>
<p>Changes do not use red or green highlighting, becuase the authors
could not convince Markdown to format the code correctly. <i>– end
note]</i></p>
</blockquote>
<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="co">// [linalg.algs.blas2.rank1], nonsymmetric rank-1 matrix update</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="co">// overwriting nonsymmetric rank-1 matrix update</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> matrix_rank_1_update<span class="op">(</span>InVec1 x, InVec2 y, OutMat A<span class="op">)</span>;</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>                              InVec1 x, InVec2 y, OutMat A<span class="op">)</span>;</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">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> matrix_rank_1_update_c<span class="op">(</span>InVec1 x, InVec2 y, OutMat A<span class="op">)</span>;</span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> matrix_rank_1_update_c<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a>                                InVec1 x, InVec2 y, OutMat A<span class="op">)</span>;</span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a>  <span class="co">// updating nonsymmetric rank-1 matrix update</span></span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>in-matrix</em> InMat, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> matrix_rank_1_update<span class="op">(</span>InVec1 x, InVec2 y, InMat E, OutMat A<span class="op">)</span>;</span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-matrix</em> InMat, <em>in-vector</em> InVec2, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb18-20"><a href="#cb18-20" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb18-21"><a href="#cb18-21" aria-hidden="true" tabindex="-1"></a>                              InVec1 x, InVec2 y, InMat E, OutMat A<span class="op">)</span>;</span>
<span id="cb18-22"><a href="#cb18-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-23"><a href="#cb18-23" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>in-matrix</em> InMat, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb18-24"><a href="#cb18-24" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> matrix_rank_1_update_c<span class="op">(</span>InVec1 x, InVec2 y, InMat E, OutMat A<span class="op">)</span>;</span>
<span id="cb18-25"><a href="#cb18-25" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>in-matrix</em> InMat, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb18-26"><a href="#cb18-26" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> matrix_rank_1_update_c<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb18-27"><a href="#cb18-27" aria-hidden="true" tabindex="-1"></a>                                InVec1 x, InVec2 y, InMat E, OutMat A<span class="op">)</span>;</span>
<span id="cb18-28"><a href="#cb18-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-29"><a href="#cb18-29" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [linalg.algs.blas2.symherrank1], symmetric or Hermitian rank-1 matrix update</span></span>
<span id="cb18-30"><a href="#cb18-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-31"><a href="#cb18-31" aria-hidden="true" tabindex="-1"></a>  <span class="co">// overwriting symmetric rank-1 matrix update </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> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-33"><a href="#cb18-33" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>Scalar alpha, InVec x, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-34"><a href="#cb18-34" 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="cb18-35"><a href="#cb18-35" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-36"><a href="#cb18-36" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb18-37"><a href="#cb18-37" aria-hidden="true" tabindex="-1"></a>                                        Scalar alpha, InVec x, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-38"><a href="#cb18-38" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-39"><a href="#cb18-39" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>InVec x, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-40"><a href="#cb18-40" 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="cb18-41"><a href="#cb18-41" aria-hidden="true" tabindex="-1"></a>           <em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-42"><a href="#cb18-42" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb18-43"><a href="#cb18-43" aria-hidden="true" tabindex="-1"></a>                                        InVec x, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-44"><a href="#cb18-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-45"><a href="#cb18-45" aria-hidden="true" tabindex="-1"></a>  <span class="co">// updating symmetric rank-1 matrix update </span></span>
<span id="cb18-46"><a href="#cb18-46" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-47"><a href="#cb18-47" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>Scalar alpha, InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-48"><a href="#cb18-48" 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="cb18-49"><a href="#cb18-49" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-50"><a href="#cb18-50" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb18-51"><a href="#cb18-51" aria-hidden="true" tabindex="-1"></a>                                        Scalar alpha, InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-52"><a href="#cb18-52" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-53"><a href="#cb18-53" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>InVec x, InMat E, OutMat A, Triangle t<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> ExecutionPolicy,</span>
<span id="cb18-55"><a href="#cb18-55" aria-hidden="true" tabindex="-1"></a>           <em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-56"><a href="#cb18-56" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb18-57"><a href="#cb18-57" aria-hidden="true" tabindex="-1"></a>                                        InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-58"><a href="#cb18-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-59"><a href="#cb18-59" aria-hidden="true" tabindex="-1"></a>  <span class="co">// overwriting Hermitian rank-1 matrix update </span></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><em>noncomplex</em> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-61"><a href="#cb18-61" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>Scalar alpha, InVec x, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-62"><a href="#cb18-62" 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="cb18-63"><a href="#cb18-63" aria-hidden="true" tabindex="-1"></a>           <em>noncomplex</em> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-64"><a href="#cb18-64" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb18-65"><a href="#cb18-65" aria-hidden="true" tabindex="-1"></a>                                        Scalar alpha, InVec x, OutMat A, Triangle t<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><em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-67"><a href="#cb18-67" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>InVec x, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-68"><a href="#cb18-68" 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="cb18-69"><a href="#cb18-69" aria-hidden="true" tabindex="-1"></a>           <em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-70"><a href="#cb18-70" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb18-71"><a href="#cb18-71" aria-hidden="true" tabindex="-1"></a>                                        InVec x, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-72"><a href="#cb18-72" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-73"><a href="#cb18-73" aria-hidden="true" tabindex="-1"></a>  <span class="co">// updating Hermitian rank-1 matrix update </span></span>
<span id="cb18-74"><a href="#cb18-74" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>noncomplex</em> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-75"><a href="#cb18-75" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>Scalar alpha, InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-76"><a href="#cb18-76" 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="cb18-77"><a href="#cb18-77" aria-hidden="true" tabindex="-1"></a>           <em>noncomplex</em> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-78"><a href="#cb18-78" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb18-79"><a href="#cb18-79" aria-hidden="true" tabindex="-1"></a>                                        Scalar alpha, InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-80"><a href="#cb18-80" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-81"><a href="#cb18-81" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb18-82"><a href="#cb18-82" 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="cb18-83"><a href="#cb18-83" aria-hidden="true" tabindex="-1"></a>           <em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb18-84"><a href="#cb18-84" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb18-85"><a href="#cb18-85" aria-hidden="true" tabindex="-1"></a>                                        InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<h2 data-number="7.4" id="rank-2-update-functions-in-synopsis"><span class="header-section-number">7.4</span> Rank-2 update functions in
synopsis<a href="#rank-2-update-functions-in-synopsis" class="self-link"></a></h2>
<blockquote>
<p>In the header <code>&lt;linalg&gt;</code> synopsis
<strong>[linalg.syn]</strong>, replace all the declarations of all the
<code>symmetric_matrix_rank_2_update</code> and
<code>hermitian_matrix_rank_2_update</code> overloads to read as
follows. <i>[Editorial Note:</i> These additions are not shown in green,
becuase the authors could not convince Markdown to format the code
correctly. <i>– end note]</i></p>
</blockquote>
<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="co">// [linalg.algs.blas2.rank2], symmetric and Hermitian rank-2 matrix updates</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">// overwriting symmetric rank-2 matrix update</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_2_update<span class="op">(</span>InVec1 x, InVec2 y, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_2_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a>                                        InVec1 x, InVec2 y, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a>  <span class="co">// updating symmetric rank-2 matrix update</span></span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat,</span>
<span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_2_update<span class="op">(</span>InVec1 x, InVec2 y, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb19-17"><a href="#cb19-17" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb19-18"><a href="#cb19-18" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat,</span>
<span id="cb19-19"><a href="#cb19-19" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb19-20"><a href="#cb19-20" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_2_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb19-21"><a href="#cb19-21" aria-hidden="true" tabindex="-1"></a>                                        InVec1 x, InVec2 y, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb19-22"><a href="#cb19-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-23"><a href="#cb19-23" aria-hidden="true" tabindex="-1"></a>  <span class="co">// overwriting Hermitian rank-2 matrix update</span></span>
<span id="cb19-24"><a href="#cb19-24" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb19-25"><a href="#cb19-25" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb19-26"><a href="#cb19-26" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_2_update<span class="op">(</span>InVec1 x, InVec2 y, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb19-27"><a href="#cb19-27" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb19-28"><a href="#cb19-28" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb19-29"><a href="#cb19-29" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_2_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb19-30"><a href="#cb19-30" aria-hidden="true" tabindex="-1"></a>                                        InVec1 x, InVec2 y, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb19-31"><a href="#cb19-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-32"><a href="#cb19-32" aria-hidden="true" tabindex="-1"></a>  <span class="co">// updating Hermitian rank-2 matrix update</span></span>
<span id="cb19-33"><a href="#cb19-33" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb19-34"><a href="#cb19-34" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat,</span>
<span id="cb19-35"><a href="#cb19-35" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb19-36"><a href="#cb19-36" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_2_update<span class="op">(</span>InVec1 x, InVec2 y, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb19-37"><a href="#cb19-37" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb19-38"><a href="#cb19-38" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat,</span>
<span id="cb19-39"><a href="#cb19-39" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb19-40"><a href="#cb19-40" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_2_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb19-41"><a href="#cb19-41" aria-hidden="true" tabindex="-1"></a>                                        InVec1 x, InVec2 y, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<h2 data-number="7.5" id="rank-k-update-functions-in-synopsis"><span class="header-section-number">7.5</span> Rank-k update functions in
synopsis<a href="#rank-k-update-functions-in-synopsis" class="self-link"></a></h2>
<blockquote>
<p>In the header <code>&lt;linalg&gt;</code> synopsis
<strong>[linalg.syn]</strong>, replace all the declarations of all the
<code>symmetric_matrix_rank_k_update</code> and
<code>hermitian_matrix_rank_k_update</code> overloads to read as
follows. <i>[Editorial Note:</i> These additions are not shown in green,
becuase the authors could not convince Markdown to format the code
correctly. <i>– end note]</i></p>
</blockquote>
<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="co">// [linalg.algs.blas3.rankk], rank-k update of a symmetric or Hermitian matrix</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">// overwriting symmetric rank-k matrix update</span></span>
<span id="cb20-4"><a href="#cb20-4" 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="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat,</span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a>      Scalar alpha, InMat A, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <span class="kw">class</span> Scalar,</span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat,</span>
<span id="cb20-12"><a href="#cb20-12" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-13"><a href="#cb20-13" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-14"><a href="#cb20-14" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-15"><a href="#cb20-15" aria-hidden="true" tabindex="-1"></a>      ExecutionPolicy<span class="op">&amp;&amp;</span> exec, Scalar alpha, InMat A, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-16"><a href="#cb20-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb20-17"><a href="#cb20-17" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-18"><a href="#cb20-18" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-19"><a href="#cb20-19" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-20"><a href="#cb20-20" aria-hidden="true" tabindex="-1"></a>      InMat A, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-21"><a href="#cb20-21" 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="cb20-22"><a href="#cb20-22" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat,</span>
<span id="cb20-23"><a href="#cb20-23" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-24"><a href="#cb20-24" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-25"><a href="#cb20-25" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-26"><a href="#cb20-26" aria-hidden="true" tabindex="-1"></a>      ExecutionPolicy<span class="op">&amp;&amp;</span> exec, InMat A, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-27"><a href="#cb20-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-28"><a href="#cb20-28" aria-hidden="true" tabindex="-1"></a>  <span class="co">// updating symmetric rank-k matrix update</span></span>
<span id="cb20-29"><a href="#cb20-29" 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="cb20-30"><a href="#cb20-30" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat1,</span>
<span id="cb20-31"><a href="#cb20-31" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb20-32"><a href="#cb20-32" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-33"><a href="#cb20-33" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-34"><a href="#cb20-34" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-35"><a href="#cb20-35" aria-hidden="true" tabindex="-1"></a>      Scalar alpha,</span>
<span id="cb20-36"><a href="#cb20-36" aria-hidden="true" tabindex="-1"></a>      InMat1 A, InMat2 E, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-37"><a href="#cb20-37" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <span class="kw">class</span> Scalar,</span>
<span id="cb20-38"><a href="#cb20-38" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat1,</span>
<span id="cb20-39"><a href="#cb20-39" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb20-40"><a href="#cb20-40" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-41"><a href="#cb20-41" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-42"><a href="#cb20-42" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-43"><a href="#cb20-43" aria-hidden="true" tabindex="-1"></a>      ExecutionPolicy<span class="op">&amp;&amp;</span> exec, Scalar alpha,</span>
<span id="cb20-44"><a href="#cb20-44" aria-hidden="true" tabindex="-1"></a>      InMat1 A, InMat2 E, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-45"><a href="#cb20-45" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb20-46"><a href="#cb20-46" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb20-47"><a href="#cb20-47" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-48"><a href="#cb20-48" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-49"><a href="#cb20-49" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-50"><a href="#cb20-50" aria-hidden="true" tabindex="-1"></a>      InMat1 A, InMat2 E, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-51"><a href="#cb20-51" 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="cb20-52"><a href="#cb20-52" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat1,</span>
<span id="cb20-53"><a href="#cb20-53" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb20-54"><a href="#cb20-54" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-55"><a href="#cb20-55" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-56"><a href="#cb20-56" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-57"><a href="#cb20-57" aria-hidden="true" tabindex="-1"></a>      ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb20-58"><a href="#cb20-58" aria-hidden="true" tabindex="-1"></a>      InMat1 A, InMat2 E, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-59"><a href="#cb20-59" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-60"><a href="#cb20-60" aria-hidden="true" tabindex="-1"></a>  <span class="co">// overwriting rank-k Hermitian matrix update</span></span>
<span id="cb20-61"><a href="#cb20-61" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>noncomplex</em> Scalar,</span>
<span id="cb20-62"><a href="#cb20-62" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat,</span>
<span id="cb20-63"><a href="#cb20-63" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-64"><a href="#cb20-64" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-65"><a href="#cb20-65" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-66"><a href="#cb20-66" aria-hidden="true" tabindex="-1"></a>      Scalar alpha, InMat A, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-67"><a href="#cb20-67" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>noncomplex</em> Scalar,</span>
<span id="cb20-68"><a href="#cb20-68" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat,</span>
<span id="cb20-69"><a href="#cb20-69" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-70"><a href="#cb20-70" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-71"><a href="#cb20-71" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-72"><a href="#cb20-72" aria-hidden="true" tabindex="-1"></a>      ExecutionPolicy<span class="op">&amp;&amp;</span> exec, Scalar alpha, InMat A, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-73"><a href="#cb20-73" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb20-74"><a href="#cb20-74" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-75"><a href="#cb20-75" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-76"><a href="#cb20-76" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-77"><a href="#cb20-77" aria-hidden="true" tabindex="-1"></a>      InMat A, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-78"><a href="#cb20-78" 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="cb20-79"><a href="#cb20-79" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat,</span>
<span id="cb20-80"><a href="#cb20-80" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-81"><a href="#cb20-81" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-82"><a href="#cb20-82" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-83"><a href="#cb20-83" aria-hidden="true" tabindex="-1"></a>      ExecutionPolicy<span class="op">&amp;&amp;</span> exec, InMat A, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-84"><a href="#cb20-84" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-85"><a href="#cb20-85" aria-hidden="true" tabindex="-1"></a>  <span class="co">// updating rank-k Hermitian matrix update</span></span>
<span id="cb20-86"><a href="#cb20-86" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>noncomplex</em> Scalar,</span>
<span id="cb20-87"><a href="#cb20-87" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat1,</span>
<span id="cb20-88"><a href="#cb20-88" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb20-89"><a href="#cb20-89" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-90"><a href="#cb20-90" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-91"><a href="#cb20-91" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-92"><a href="#cb20-92" aria-hidden="true" tabindex="-1"></a>      Scalar alpha,</span>
<span id="cb20-93"><a href="#cb20-93" aria-hidden="true" tabindex="-1"></a>      InMat1 A, InMat2 E, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-94"><a href="#cb20-94" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>noncomplex</em> Scalar,</span>
<span id="cb20-95"><a href="#cb20-95" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat1,</span>
<span id="cb20-96"><a href="#cb20-96" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb20-97"><a href="#cb20-97" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-98"><a href="#cb20-98" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-99"><a href="#cb20-99" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-100"><a href="#cb20-100" aria-hidden="true" tabindex="-1"></a>      ExecutionPolicy<span class="op">&amp;&amp;</span> exec, Scalar alpha,</span>
<span id="cb20-101"><a href="#cb20-101" aria-hidden="true" tabindex="-1"></a>      InMat1 A, InMat2 E, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-102"><a href="#cb20-102" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb20-103"><a href="#cb20-103" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb20-104"><a href="#cb20-104" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-105"><a href="#cb20-105" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-106"><a href="#cb20-106" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-107"><a href="#cb20-107" aria-hidden="true" tabindex="-1"></a>      InMat1 A, InMat2 E, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb20-108"><a href="#cb20-108" 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="cb20-109"><a href="#cb20-109" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat1,</span>
<span id="cb20-110"><a href="#cb20-110" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb20-111"><a href="#cb20-111" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb20-112"><a href="#cb20-112" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb20-113"><a href="#cb20-113" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb20-114"><a href="#cb20-114" aria-hidden="true" tabindex="-1"></a>      ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb20-115"><a href="#cb20-115" aria-hidden="true" tabindex="-1"></a>      InMat1 A, InMat2 E, OutMat C, Triangle t<span class="op">)</span>;</span></code></pre></div>
<h2 data-number="7.6" id="rank-2k-update-functions-in-synopsis"><span class="header-section-number">7.6</span> Rank-2k update functions in
synopsis<a href="#rank-2k-update-functions-in-synopsis" class="self-link"></a></h2>
<blockquote>
<p>In the header <code>&lt;linalg&gt;</code> synopsis
<strong>[linalg.syn]</strong>, replace all the declarations of all the
<code>symmetric_matrix_rank_2k_update</code> and
<code>hermitian_matrix_rank_2k_update</code> overloads to read as
follows. <i>[Editorial Note:</i> These additions are not shown in green,
becuase the authors could not convince Markdown to format the code
correctly. <i>– end note]</i></p>
</blockquote>
<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="co">// [linalg.algs.blas3.rank2k], rank-2k update of a symmetric or Hermitian matrix</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">// overwriting symmetric rank-2k matrix update</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1, <em>in-matrix</em> InMat2,</span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_2k_update<span class="op">(</span>InMat1 A, InMat2 B, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb21-7"><a href="#cb21-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="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat1, <em>in-matrix</em> InMat2,</span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_2k_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a>                                         InMat1 A, InMat2 B, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb21-12"><a href="#cb21-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-13"><a href="#cb21-13" aria-hidden="true" tabindex="-1"></a>  <span class="co">// updating symmetric rank-2k matrix update</span></span>
<span id="cb21-14"><a href="#cb21-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1, <em>in-matrix</em> InMat2,</span>
<span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat3,</span>
<span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_2k_update<span class="op">(</span>InMat1 A, InMat2 B, InMat3 E, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb21-18"><a href="#cb21-18" 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="cb21-19"><a href="#cb21-19" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat1, <em>in-matrix</em> InMat2,</span>
<span id="cb21-20"><a href="#cb21-20" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat3,</span>
<span id="cb21-21"><a href="#cb21-21" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb21-22"><a href="#cb21-22" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> symmetric_matrix_rank_2k_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb21-23"><a href="#cb21-23" aria-hidden="true" tabindex="-1"></a>                                         InMat1 A, InMat2 B, InMat3 E, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb21-24"><a href="#cb21-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-25"><a href="#cb21-25" aria-hidden="true" tabindex="-1"></a>  <span class="co">// overwriting Hermitian rank-2k matrix update</span></span>
<span id="cb21-26"><a href="#cb21-26" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1, <em>in-matrix</em> InMat2,</span>
<span id="cb21-27"><a href="#cb21-27" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb21-28"><a href="#cb21-28" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_2k_update<span class="op">(</span>InMat1 A, InMat2 B, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb21-29"><a href="#cb21-29" 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="cb21-30"><a href="#cb21-30" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat1, <em>in-matrix</em> InMat2,</span>
<span id="cb21-31"><a href="#cb21-31" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb21-32"><a href="#cb21-32" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_2k_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb21-33"><a href="#cb21-33" aria-hidden="true" tabindex="-1"></a>                                         InMat1 A, InMat2 B, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb21-34"><a href="#cb21-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-35"><a href="#cb21-35" aria-hidden="true" tabindex="-1"></a>  <span class="co">// updating Hermitian rank-2k matrix update</span></span>
<span id="cb21-36"><a href="#cb21-36" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1, <em>in-matrix</em> InMat2,</span>
<span id="cb21-37"><a href="#cb21-37" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat3,</span>
<span id="cb21-38"><a href="#cb21-38" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb21-39"><a href="#cb21-39" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_2k_update<span class="op">(</span>InMat1 A, InMat2 B, InMat3 E, OutMat C, Triangle t<span class="op">)</span>;</span>
<span id="cb21-40"><a href="#cb21-40" 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="cb21-41"><a href="#cb21-41" aria-hidden="true" tabindex="-1"></a>           <em>in-matrix</em> InMat1, <em>in-matrix</em> InMat2,</span>
<span id="cb21-42"><a href="#cb21-42" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-in-matrix</em> InMat3,</span>
<span id="cb21-43"><a href="#cb21-43" aria-hidden="true" tabindex="-1"></a>           <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb21-44"><a href="#cb21-44" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> hermitian_matrix_rank_2k_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb21-45"><a href="#cb21-45" aria-hidden="true" tabindex="-1"></a>                                         InMat1 A, InMat2 B, InMat3 E, OutMat C, Triangle t<span class="op">)</span>;</span></code></pre></div>
<h2 data-number="7.7" id="specification-of-nonsymmetric-rank-1-update-functions"><span class="header-section-number">7.7</span> Specification of nonsymmetric
rank-1 update functions<a href="#specification-of-nonsymmetric-rank-1-update-functions" class="self-link"></a></h2>
<blockquote>
<p>Replace the entire contents of [linalg.algs.blas2.rank1] with the
following.</p>
</blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following elements apply to all functions in
[linalg.algs.blas2.rank1].</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Mandates</em>:</p>
<p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<em><code>possibly-multipliable</code></em><code>&lt;OutMat, InVec2, InVec1&gt;()</code>
is <code>true</code>, and</p>
<p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<em><code>possibly-addable</code></em><code>(A, E, A)</code> is
<code>true</code> for those overloads that take an <code>E</code>
parameter.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Preconditions</em>:</p>
<p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
<code>multipliable(A, y, x)</code> is <code>true</code>, and</p>
<p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
<em><code>addable</code></em><code>(A, E, A)</code> is <code>true</code>
for those overloads that take an <code>E</code> parameter.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Complexity</em>: <span class="math inline"><em>O</em>(</span>
<code>x.extent(0)</code> × <code>y.extent(0)</code> <span class="math inline">)</span>.</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">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> matrix_rank_1_update<span class="op">(</span>InVec1 x, InVec2 y, OutMat A<span class="op">)</span>;</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec, InVec1 x, InVec2 y, OutMat A<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
These functions perform a overwriting nonsymmetric nonconjugated rank-1
update.</p>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xGER</code> (for real element types) and <code>xGERU</code> (for
complex element types)[bib]. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Effects</em>: Computes <span class="math inline"><em>A</em> = <em>x</em><em>y</em><sup><em>T</em></sup></span>.</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><em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>in-matrix</em> InMat, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> matrix_rank_1_update<span class="op">(</span>InVec1 x, InVec2 y, InMat E, OutMat A<span class="op">)</span>;</span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>in-matrix</em> InMat, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec, InVec1 x, InVec2 y, InMat E, OutMat A<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
These functions perform an updating nonsymmetric nonconjugated rank-1
update.</p>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xGER</code> (for real element types) and <code>xGERU</code> (for
complex element types)[bib]. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Effects</em>: Computes <span class="math inline"><em>A</em> = <em>E</em> + <em>x</em><em>y</em><sup><em>T</em></sup></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Remarks</em>: <code>A</code> may alias <code>E</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">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> matrix_rank_1_update_c<span class="op">(</span>InVec1 x, InVec2 y, OutMat A<span class="op">)</span>;</span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2, <em>out-matrix</em> OutMat<span class="op">&gt;</span></span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> matrix_rank_1_update_c<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec, InVec1 x, InVec2 y, OutMat A<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span> These
functions perform a overwriting nonsymmetric conjugated rank-1
update.</p>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xGER</code> (for real element types) and <code>xGERC</code> (for
complex element types)[bib]. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Effects</em>:</p>
<p><span class="marginalizedparent"><a class="marginalized">(11.1)</a></span> For
the overloads without an <code>ExecutionPolicy</code> argument,
equivalent to:</p>
<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>matrix_rank_1_update<span class="op">(</span>x, conjugated<span class="op">(</span>y<span class="op">)</span>, A<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">(11.2)</a></span>
otherwise, equivalent to:</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>matrix_rank_1_update<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>ExecutionPolicy<span class="op">&gt;(</span>exec<span class="op">)</span>, x, conjugated<span class="op">(</span>y<span class="op">)</span>, A<span class="op">)</span>;</span></code></pre></div>
<h2 data-number="7.8" id="specification-of-symmetric-and-hermitian-rank-1-update-functions"><span class="header-section-number">7.8</span> Specification of symmetric and
Hermitian rank-1 update functions<a href="#specification-of-symmetric-and-hermitian-rank-1-update-functions" class="self-link"></a></h2>
<blockquote>
<p>Replace the entire contents of [linalg.algs.blas2.symherrank1] with
the following.</p>
</blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<i>[Note:</i> These functions correspond to the BLAS functions
<code>xSYR</code>, <code>xSPR</code>, <code>xHER</code>, and
<code>xHPR</code>[bib]. 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>T</em></sup></span>
otherwise. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The following elements apply to all functions in
[linalg.algs.blas2.symherrank1].</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
For any function <code>F</code> in this section that takes a parameter
named <code>t</code>, an <code>InMat</code> template parameter, and a
function parameter <code>InMat E</code>, <code>t</code> applies to
accesses done through the parameter <code>E</code>. <code>F</code> will
only access the triangle of <code>E</code> specified by <code>t</code>.
For accesses of diagonal elements <code>E[i, i]</code>, <code>F</code>
will use the value
<em><code>real-if-needed</code></em><code>(E[i, i])</code> if the name
of <code>F</code> starts with <code>hermitian</code>. For accesses
<code>E[i, j]</code> outside the triangle specified by <code>t</code>,
<code>F</code> will use the value</p>
<p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
<em><code>conj-if-needed</code></em><code>(E[j, i])</code> if the name
of <code>F</code> starts with <code>hermitian</code>, or</p>
<p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
<code>E[j, i]</code> if the name of <code>F</code> starts with
<code>symmetric</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates</em>:</p>
<p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> If
<code>OutMat</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.2)</a></span> If
the function has an <code>InMat</code> template parameter and
<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.3)</a></span>
<em><code>compatible-static-extents</code></em><code>&lt;decltype(A), decltype(A)&gt;(0, 1)</code>
is <code>true</code>;</p>
<p><span class="marginalizedparent"><a class="marginalized">(4.4)</a></span>
<em><code>compatible-static-extents</code></em><code>&lt;decltype(A), decltype(x)&gt;(0, 0)</code>
is <code>true</code>; and</p>
<p><span class="marginalizedparent"><a class="marginalized">(4.5)</a></span>
<em><code>possibly-addable</code></em><code>&lt;decltype(A), decltype(E), decltype(A)&gt;</code>
is <code>true</code> for those overloads that take an <code>E</code>
parameter.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Preconditions</em>:</p>
<p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>,</p>
<p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
<code>A.extent(0)</code> equals <code>x.extent(0)</code>, and</p>
<p><span class="marginalizedparent"><a class="marginalized">(5.3)</a></span>
<em><code>addable</code></em><code>(A, E, A)</code> is <code>true</code>
for those overloads that take an <code>E</code> parameter.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Complexity</em>: <span class="math inline"><em>O</em>(</span>
<code>x.extent(0)</code> × <code>x.extent(0)</code> <span class="math inline">)</span>.</p>
<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">template</span><span class="op">&lt;</span><span class="kw">class</span> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>Scalar alpha, InVec x, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb27-3"><a href="#cb27-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="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a>                                      Scalar alpha, InVec x, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
These functions perform an overwriting symmetric rank-1 update of the
symmetric matrix <code>A</code>, taking into account the
<code>Triangle</code> parameter that applies to <code>A</code>
([linalg.general]).</p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Effects</em>: Computes <span class="math inline"><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>.</p>
<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">template</span><span class="op">&lt;</span><em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>InVec x, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb28-3"><a href="#cb28-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="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec, InVec x, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
These functions perform an overwriting symmetric rank-1 update of the
symmetric matrix <code>A</code>, taking into account the
<code>Triangle</code> parameter that applies to <code>A</code>
([linalg.general]).</p>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Effects</em>: Computes <span class="math inline"><em>A</em> = <em>x</em><em>x</em><sup><em>T</em></sup></span>.</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">template</span><span class="op">&lt;</span><span class="kw">class</span> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>Scalar alpha, InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb29-3"><a href="#cb29-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="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a>                                      Scalar alpha, InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span> These
functions perform an updating symmetric rank-1 update of the symmetric
matrix <code>A</code> using the symmetric matrix <code>E</code>, taking
into account the <code>Triangle</code> parameter that applies to
<code>A</code> and <code>E</code> ([linalg.general]).</p>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Effects</em>: Computes <span class="math inline"><em>A</em> = <em>E</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>.</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">template</span><span class="op">&lt;</span><em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb30-3"><a href="#cb30-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="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> symmetric_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a>                                      InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">13</a></span> These
functions perform an updating symmetric rank-1 update of the symmetric
matrix <code>A</code> using the symmetric matrix <code>E</code>, taking
into account the <code>Triangle</code> parameter that applies to
<code>A</code> and <code>E</code> ([linalg.general]).</p>
<p><span class="marginalizedparent"><a class="marginalized">14</a></span>
<em>Effects</em>: Computes <span class="math inline"><em>A</em> = <em>E</em> + <em>x</em><em>x</em><sup><em>T</em></sup></span>.</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">template</span><span class="op">&lt;</span><em>noncomplex</em> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>Scalar alpha, InVec x, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb31-3"><a href="#cb31-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="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a>         <em>noncomplex</em> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb31-6"><a href="#cb31-6" aria-hidden="true" tabindex="-1"></a>                                      Scalar alpha, InVec x, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">15</a></span> These
functions perform an overwriting Hermitian rank-1 update of the
Hermitian matrix <code>A</code>, taking into account the
<code>Triangle</code> parameter that applies to <code>A</code>
([linalg.general]).</p>
<p><span class="marginalizedparent"><a class="marginalized">16</a></span>
<em>Effects</em>: Computes <span class="math inline"><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>.</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><em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>InVec x, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb32-3"><a href="#cb32-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="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec, InVec x, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">17</a></span> These
functions perform an overwriting Hermitian rank-1 update of the
Hermitian matrix <code>A</code>, taking into account the
<code>Triangle</code> parameter that applies to <code>A</code>
([linalg.general]).</p>
<p><span class="marginalizedparent"><a class="marginalized">18</a></span>
<em>Effects</em>: Computes <span class="math inline"><em>A</em> = <em>x</em><em>x</em><sup><em>T</em></sup></span>.</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="kw">template</span><span class="op">&lt;</span><em>noncomplex</em> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>Scalar alpha, InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb33-3"><a href="#cb33-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="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a>         <em>noncomplex</em> Scalar, <em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a>                                      Scalar alpha, InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">19</a></span> These
functions perform an updating Hermitian rank-1 update of the Hermitian
matrix <code>A</code> using the Hermitian matrix <code>E</code>, taking
into account the <code>Triangle</code> parameter that applies to
<code>A</code> and <code>E</code> ([linalg.general]).</p>
<p><span class="marginalizedparent"><a class="marginalized">20</a></span>
<em>Effects</em>: Computes <span class="math inline"><em>A</em> = <em>E</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>.</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><em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb34-3"><a href="#cb34-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="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a>         <em>in-vector</em> InVec, <em>possibly-packed-in-matrix</em> InMat, <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> hermitian_matrix_rank_1_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a>                                      InVec x, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">21</a></span> These
functions perform an updating Hermitian rank-1 update of the Hermitian
matrix <code>A</code> using the Hermitian matrix <code>E</code>, taking
into account the <code>Triangle</code> parameter that applies to
<code>A</code> and <code>E</code> ([linalg.general]).</p>
<p><span class="marginalizedparent"><a class="marginalized">22</a></span>
<em>Effects</em>: Computes <span class="math inline"><em>A</em> = <em>E</em> + <em>x</em><em>x</em><sup><em>T</em></sup></span>.</p>
<h2 data-number="7.9" id="specification-of-symmetric-and-hermitian-rank-2-update-functions"><span class="header-section-number">7.9</span> Specification of symmetric and
Hermitian rank-2 update functions<a href="#specification-of-symmetric-and-hermitian-rank-2-update-functions" class="self-link"></a></h2>
<blockquote>
<p>Replace the entire contents of [linalg.algs.blas2.rank2] with the
following.</p>
</blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<i>[Note:</i> These functions correspond to the BLAS functions
<code>xSYR2</code>, <code>xSPR2</code>, <code>xHER2</code>, and
<code>xHPR2</code> [bib]. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The following elements apply to all functions in
[linalg.algs.blas2.rank2].</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
For any function <code>F</code> in this section that takes a parameter
named <code>t</code>, an <code>InMat</code> template parameter, and a
function parameter <code>InMat E</code>, <code>t</code> applies to
accesses done through the parameter <code>E</code>. <code>F</code> will
only access the triangle of <code>E</code> specified by <code>t</code>.
For accesses of diagonal elements <code>E[i, i]</code>, <code>F</code>
will use the value
<em><code>real-if-needed</code></em><code>(E[i, i])</code> if the name
of <code>F</code> starts with <code>hermitian</code>. For accesses
<code>E[i, j]</code> outside the triangle specified by <code>t</code>,
<code>F</code> will use the value</p>
<p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
<em><code>conj-if-needed</code></em><code>(E[j, i])</code> if the name
of <code>F</code> starts with <code>hermitian</code>, or</p>
<p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
<code>E[j, i]</code> if the name of <code>F</code> starts with
<code>symmetric</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates</em>:</p>
<p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> If
<code>OutMat</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.2)</a></span> If
the function has an <code>InMat</code> template parameter and
<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.3)</a></span>
<em><code>compatible-static-extents</code></em><code>&lt;decltype(A), decltype(A)&gt;(0, 1)</code>
is <code>true</code>;</p>
<p><span class="marginalizedparent"><a class="marginalized">(4.4)</a></span>
<em><code>possibly-multipliable</code></em><code>&lt;decltype(A), decltype(x), decltype(y)&gt;()</code>
is <code>true</code>; and</p>
<p><span class="marginalizedparent"><a class="marginalized">(4.5)</a></span>
<em><code>possibly-addable</code></em><code>&lt;decltype(A), decltype(E), decltype(A)&gt;</code>
is <code>true</code> for those overloads that take an <code>E</code>
parameter.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Preconditions</em>:</p>
<p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span>
<code>A.extent(0)</code> equals <code>A.extent(1)</code>,</p>
<p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
<em><code>multipliable</code></em><code>(A, x, y)</code> is
<code>true</code>, and</p>
<p><span class="marginalizedparent"><a class="marginalized">(5.3)</a></span>
<em><code>addable</code></em><code>(A, E, A)</code> is <code>true</code>
for those overloads that take an <code>E</code> parameter.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Complexity</em>: <span class="math inline"><em>O</em>(</span>
<code>x.extent(0)</code> × <code>y.extent(0)</code> <span class="math inline">)</span>.</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">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> symmetric_matrix_rank_2_update<span class="op">(</span>InVec1 x, InVec2 y, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb35-6"><a href="#cb35-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> symmetric_matrix_rank_2_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb35-7"><a href="#cb35-7" aria-hidden="true" tabindex="-1"></a>                                      InVec1 x, InVec2 y, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
These functions perform an overwriting symmetric rank-2 update of the
symmetric matrix <code>A</code>, taking into account the
<code>Triangle</code> parameter that applies to <code>A</code>
([linalg.general]).</p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
Effects: Computes <span class="math inline"><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>.</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">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-in-matrix</em> InMat,</span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> symmetric_matrix_rank_2_update<span class="op">(</span>InVec1 x, InVec2 y, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-in-matrix</em> InMat,</span>
<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> symmetric_matrix_rank_2_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb36-9"><a href="#cb36-9" aria-hidden="true" tabindex="-1"></a>                                      InVec1 x, InVec2 y, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
These functions perform an updating symmetric rank-2 update of the
symmetric matrix <code>A</code> using the symmetric matrix
<code>E</code>, taking into account the <code>Triangle</code> parameter
that applies to <code>A</code> and <code>E</code>
([linalg.general]).</p>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
Effects: Computes <span class="math inline"><em>A</em> = <em>E</em> + <em>x</em><em>y</em><sup><em>T</em></sup> + <em>y</em><em>x</em><sup><em>T</em></sup></span>.</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">template</span><span class="op">&lt;</span><em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> hermitian_matrix_rank_2_update<span class="op">(</span>InVec1 x, InVec2 y, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb37-5"><a href="#cb37-5" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb37-6"><a href="#cb37-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> hermitian_matrix_rank_2_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb37-7"><a href="#cb37-7" aria-hidden="true" tabindex="-1"></a>                                      InVec1 x, InVec2 y, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span> These
functions perform an overwriting Hermitian rank-2 update of the
Hermitian matrix <code>A</code>, taking into account the
<code>Triangle</code> parameter that applies to <code>A</code>
([linalg.general]).</p>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
Effects: Computes <span class="math inline"><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>.</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><em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-in-matrix</em> InMat,</span>
<span id="cb38-3"><a href="#cb38-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb38-4"><a href="#cb38-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> hermitian_matrix_rank_2_update<span class="op">(</span>InVec1 x, InVec2 y, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span>
<span id="cb38-5"><a href="#cb38-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ExecutionPolicy, <em>in-vector</em> InVec1, <em>in-vector</em> InVec2,</span>
<span id="cb38-6"><a href="#cb38-6" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-in-matrix</em> InMat,</span>
<span id="cb38-7"><a href="#cb38-7" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat, <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb38-8"><a href="#cb38-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> hermitian_matrix_rank_2_update<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb38-9"><a href="#cb38-9" aria-hidden="true" tabindex="-1"></a>                                      InVec1 x, InVec2 y, InMat E, OutMat A, Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">13</a></span> These
functions perform an updating Hermitian rank-2 update of the Hermitian
matrix <code>A</code> using the Hermitian matrix <code>E</code>, taking
into account the <code>Triangle</code> parameter that applies to
<code>A</code> and <code>E</code> ([linalg.general]).</p>
<p><span class="marginalizedparent"><a class="marginalized">14</a></span>
Effects: Computes <span class="math inline"><em>A</em> = <em>E</em> + <em>x</em><em>y</em><sup><em>H</em></sup> + <em>y</em><em>x</em><sup><em>H</em></sup></span>.</p>
<h2 data-number="7.10" id="specification-of-rank-k-update-functions"><span class="header-section-number">7.10</span> Specification of rank-k update
functions<a href="#specification-of-rank-k-update-functions" class="self-link"></a></h2>
<blockquote>
<p>Replace the entire contents of [linalg.algs.blas3.rankk] with the
following.</p>
</blockquote>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xSYRK</code> and <code>xHERK</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following elements apply to all functions in
[linalg.algs.blas3.rankk].</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
For any function <code>F</code> in this section that takes a parameter
named <code>t</code>, an <code>InMat2</code> template parameter, and a
function parameter <code>InMat2 E</code>, <code>t</code> applies to
accesses done through the parameter <code>E</code>. <code>F</code> will
only access the triangle of <code>E</code> specified by <code>t</code>.
For accesses of diagonal elements <code>E[i, i]</code>, <code>F</code>
will use the value
<em><code>real-if-needed</code></em><code>(E[i, i])</code> if the name
of <code>F</code> starts with <code>hermitian</code>. For accesses
<code>E[i, j]</code> outside the triangle specified by <code>t</code>,
<code>F</code> will use the value</p>
<p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<em><code>conj-if-needed</code></em><code>(E[j, i])</code> if the name
of <code>F</code> starts with <code>hermitian</code>, or</p>
<p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>E[j, i]</code> if the name of <code>F</code> starts with
<code>symmetric</code>.</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
<code>OutMat</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></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> If
the function takes an <code>InMat2</code> template parameter and if
<code>InMat2</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></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span>
<em><code>possibly-multipliable</code></em><code>&lt;decltype(A), decltype(transposed(A)), decltype(C)&gt;</code>
is <code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.4)</a></span>
<em><code>possibly-addable</code></em><code>&lt;decltype(C), decltype(E), decltype(C)&gt;</code>
is <code>true</code> for those overloads that take an <code>E</code>
parameter.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<em><code>multipliable</code></em><code>(A, transposed(A), C)</code> is
<code>true</code>. <i>[Note:</i> This implies that <code>C</code> is
square. <i>– end note]</i></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
<em><code>addable</code></em><code>(C, E, C)</code> is <code>true</code>
for those overloads that take an <code>E</code> parameter.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Complexity:</em> <span class="math inline"><em>O</em>(</span>
<code>A.extent(0)</code> <span class="math inline">⋅</span>
<code>A.extent(1)</code> <span class="math inline">⋅</span>
<code>A.extent(0)</code> <span class="math inline">)</span>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Remarks:</em> <code>C</code> may alias <code>E</code> for those
overloads that take an <code>E</code> parameter.</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">template</span><span class="op">&lt;</span><span class="kw">class</span> Scalar,</span>
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a>  Scalar alpha,</span>
<span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb39-10"><a href="#cb39-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="cb39-11"><a href="#cb39-11" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Scalar,</span>
<span id="cb39-12"><a href="#cb39-12" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb39-13"><a href="#cb39-13" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb39-14"><a href="#cb39-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb39-15"><a href="#cb39-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb39-16"><a href="#cb39-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb39-17"><a href="#cb39-17" aria-hidden="true" tabindex="-1"></a>  Scalar alpha,</span>
<span id="cb39-18"><a href="#cb39-18" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb39-19"><a href="#cb39-19" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb39-20"><a href="#cb39-20" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Effects:</em> Computes <span class="math inline"><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>.</p>
<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">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb40-8"><a href="#cb40-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="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb40-12"><a href="#cb40-12" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb40-13"><a href="#cb40-13" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb40-14"><a href="#cb40-14" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb40-15"><a href="#cb40-15" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb40-16"><a href="#cb40-16" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em> = <em>A</em><em>A</em><sup><em>T</em></sup></span>.</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">template</span><span class="op">&lt;</span><em>noncomplex</em> Scalar,</span>
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a>  Scalar alpha,</span>
<span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb41-8"><a href="#cb41-8" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb41-9"><a href="#cb41-9" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb41-10"><a href="#cb41-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="cb41-11"><a href="#cb41-11" aria-hidden="true" tabindex="-1"></a>         <em>noncomplex</em> Scalar,</span>
<span id="cb41-12"><a href="#cb41-12" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb41-13"><a href="#cb41-13" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb41-14"><a href="#cb41-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb41-15"><a href="#cb41-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb41-16"><a href="#cb41-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb41-17"><a href="#cb41-17" aria-hidden="true" tabindex="-1"></a>  Scalar alpha,</span>
<span id="cb41-18"><a href="#cb41-18" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb41-19"><a href="#cb41-19" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb41-20"><a href="#cb41-20" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Effects:</em> Computes <span class="math inline"><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>.</p>
<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">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat,</span>
<span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb42-3"><a href="#cb42-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb42-5"><a href="#cb42-5" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb42-6"><a href="#cb42-6" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb42-7"><a href="#cb42-7" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb42-8"><a href="#cb42-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="cb42-9"><a href="#cb42-9" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat,</span>
<span id="cb42-10"><a href="#cb42-10" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb42-11"><a href="#cb42-11" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb42-12"><a href="#cb42-12" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb42-13"><a href="#cb42-13" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb42-14"><a href="#cb42-14" aria-hidden="true" tabindex="-1"></a>  InMat A,</span>
<span id="cb42-15"><a href="#cb42-15" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb42-16"><a href="#cb42-16" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em> = <em>A</em><em>A</em><sup><em>H</em></sup></span>.</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">template</span><span class="op">&lt;</span><span class="kw">class</span> Scalar,</span>
<span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb43-3"><a href="#cb43-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb43-4"><a href="#cb43-4" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb43-5"><a href="#cb43-5" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb43-6"><a href="#cb43-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb43-7"><a href="#cb43-7" aria-hidden="true" tabindex="-1"></a>  Scalar alpha,</span>
<span id="cb43-8"><a href="#cb43-8" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb43-9"><a href="#cb43-9" aria-hidden="true" tabindex="-1"></a>  InMat2 E,</span>
<span id="cb43-10"><a href="#cb43-10" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb43-11"><a href="#cb43-11" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb43-12"><a href="#cb43-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="cb43-13"><a href="#cb43-13" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Scalar,</span>
<span id="cb43-14"><a href="#cb43-14" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb43-15"><a href="#cb43-15" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb43-16"><a href="#cb43-16" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb43-17"><a href="#cb43-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb43-18"><a href="#cb43-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb43-19"><a href="#cb43-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb43-20"><a href="#cb43-20" aria-hidden="true" tabindex="-1"></a>  Scalar alpha,</span>
<span id="cb43-21"><a href="#cb43-21" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb43-22"><a href="#cb43-22" aria-hidden="true" tabindex="-1"></a>  InMat2 E,</span>
<span id="cb43-23"><a href="#cb43-23" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb43-24"><a href="#cb43-24" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em> = <em>E</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>.</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">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb44-2"><a href="#cb44-2" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb44-3"><a href="#cb44-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb44-4"><a href="#cb44-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb44-5"><a href="#cb44-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb44-6"><a href="#cb44-6" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb44-7"><a href="#cb44-7" aria-hidden="true" tabindex="-1"></a>  InMat2 E,</span>
<span id="cb44-8"><a href="#cb44-8" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb44-9"><a href="#cb44-9" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb44-10"><a href="#cb44-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="cb44-11"><a href="#cb44-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb44-12"><a href="#cb44-12" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb44-13"><a href="#cb44-13" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb44-14"><a href="#cb44-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb44-15"><a href="#cb44-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb44-16"><a href="#cb44-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb44-17"><a href="#cb44-17" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb44-18"><a href="#cb44-18" aria-hidden="true" tabindex="-1"></a>  InMat2 E,</span>
<span id="cb44-19"><a href="#cb44-19" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb44-20"><a href="#cb44-20" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em> = <em>E</em> + <em>A</em><em>A</em><sup><em>T</em></sup></span>.</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">template</span><span class="op">&lt;</span><em>noncomplex</em> Scalar,</span>
<span id="cb45-2"><a href="#cb45-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb45-3"><a href="#cb45-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb45-4"><a href="#cb45-4" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb45-5"><a href="#cb45-5" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb45-6"><a href="#cb45-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb45-7"><a href="#cb45-7" aria-hidden="true" tabindex="-1"></a>  Scalar alpha,</span>
<span id="cb45-8"><a href="#cb45-8" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb45-9"><a href="#cb45-9" aria-hidden="true" tabindex="-1"></a>  InMat2 E,</span>
<span id="cb45-10"><a href="#cb45-10" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb45-11"><a href="#cb45-11" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb45-12"><a href="#cb45-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="cb45-13"><a href="#cb45-13" aria-hidden="true" tabindex="-1"></a>         <em>noncomplex</em> Scalar,</span>
<span id="cb45-14"><a href="#cb45-14" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb45-15"><a href="#cb45-15" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb45-16"><a href="#cb45-16" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb45-17"><a href="#cb45-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb45-18"><a href="#cb45-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb45-19"><a href="#cb45-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb45-20"><a href="#cb45-20" aria-hidden="true" tabindex="-1"></a>  Scalar alpha,</span>
<span id="cb45-21"><a href="#cb45-21" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb45-22"><a href="#cb45-22" aria-hidden="true" tabindex="-1"></a>  InMat2 E,</span>
<span id="cb45-23"><a href="#cb45-23" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb45-24"><a href="#cb45-24" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em> = <em>E</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>.</p>
<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><em>in-matrix</em> InMat1,</span>
<span id="cb46-2"><a href="#cb46-2" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb46-3"><a href="#cb46-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb46-4"><a href="#cb46-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb46-5"><a href="#cb46-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb46-6"><a href="#cb46-6" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb46-7"><a href="#cb46-7" aria-hidden="true" tabindex="-1"></a>  InMat2 E,</span>
<span id="cb46-8"><a href="#cb46-8" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb46-9"><a href="#cb46-9" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb46-10"><a href="#cb46-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="cb46-11"><a href="#cb46-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb46-12"><a href="#cb46-12" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-in-matrix</em> InMat2,</span>
<span id="cb46-13"><a href="#cb46-13" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb46-14"><a href="#cb46-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb46-15"><a href="#cb46-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_k_update<span class="op">(</span></span>
<span id="cb46-16"><a href="#cb46-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb46-17"><a href="#cb46-17" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb46-18"><a href="#cb46-18" aria-hidden="true" tabindex="-1"></a>  InMat2 E,</span>
<span id="cb46-19"><a href="#cb46-19" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb46-20"><a href="#cb46-20" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em> = <em>E</em> + <em>A</em><em>A</em><sup><em>H</em></sup></span>.</p>
<h2 data-number="7.11" id="specification-of-rank-2k-update-functions"><span class="header-section-number">7.11</span> Specification of rank-2k
update functions<a href="#specification-of-rank-2k-update-functions" class="self-link"></a></h2>
<blockquote>
<p>Replace the entire contents of [linalg.algs.blas3.rank2k] with the
following.</p>
</blockquote>
<p><i>[Note:</i> These functions correspond to the BLAS functions
<code>xSYR2K</code> and <code>xHER2K</code>. <i>– end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following elements apply to all functions in
[linalg.algs.blas3.rank2k].</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
For any function <code>F</code> in this section that takes a parameter
named <code>t</code>, an <code>InMat3</code> template parameter, and a
function parameter <code>InMat3 E</code>, <code>t</code> applies to
accesses done through the parameter <code>E</code>. <code>F</code> will
only access the triangle of <code>E</code> specified by <code>t</code>.
For accesses of diagonal elements <code>E[i, i]</code>, <code>F</code>
will use the value
<em><code>real-if-needed</code></em><code>(E[i, i])</code> if the name
of <code>F</code> starts with <code>hermitian</code>. For accesses
<code>E[i, j]</code> outside the triangle specified by <code>t</code>,
<code>F</code> will use the value</p>
<p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<em><code>conj-if-needed</code></em><code>(E[j, i])</code> if the name
of <code>F</code> starts with <code>hermitian</code>, or</p>
<p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>E[j, i]</code> if the name of <code>F</code> starts with
<code>symmetric</code>.</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
<code>OutMat</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></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> If
the function takes an <code>InMat3</code> template parameter and if
<code>InMat3</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></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span>
<em><code>possibly-multipliable</code></em><code>&lt;decltype(A), decltype(transposed(B)), decltype(C)&gt;</code>
is <code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.4)</a></span>
<em><code>possibly-multipliable</code></em><code>&lt;decltype(B), decltype(transposed(A)), decltype(C)&gt;</code>
is <code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.5)</a></span>
<em><code>possibly-addable</code></em><code>&lt;decltype(C), decltype(E), decltype(C)&gt;</code>
is <code>true</code> for those overloads that take an <code>E</code>
parameter.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<em><code>multipliable</code></em><code>(A, transposed(B), C)</code> is
<code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
<em><code>multipliable</code></em><code>(B, transposed(A), C)</code> is
<code>true</code>. <i>[Note:</i> This and the previous imply that
<code>C</code> is square. <i>– end note]</i></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span>
<em><code>addable</code></em><code>(C, E, C)</code> is <code>true</code>
for those overloads that take an <code>E</code> parameter.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Complexity:</em> <span class="math inline"><em>O</em>(</span>
<code>A.extent(0)</code> <span class="math inline">⋅</span>
<code>A.extent(1)</code> <span class="math inline">⋅</span>
<code>B.extent(0)</code> <span class="math inline">)</span></p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Remarks:</em> <code>C</code> may alias <code>E</code> for those
overloads that take an <code>E</code> parameter.</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="kw">template</span><span class="op">&lt;</span><em>in-matrix</em> InMat1,</span>
<span id="cb47-2"><a href="#cb47-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb47-3"><a href="#cb47-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb47-4"><a href="#cb47-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb47-5"><a href="#cb47-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb47-6"><a href="#cb47-6" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb47-7"><a href="#cb47-7" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb47-8"><a href="#cb47-8" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb47-9"><a href="#cb47-9" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb47-10"><a href="#cb47-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="cb47-11"><a href="#cb47-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb47-12"><a href="#cb47-12" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb47-13"><a href="#cb47-13" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb47-14"><a href="#cb47-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb47-15"><a href="#cb47-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb47-16"><a href="#cb47-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb47-17"><a href="#cb47-17" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb47-18"><a href="#cb47-18" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb47-19"><a href="#cb47-19" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb47-20"><a href="#cb47-20" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Effects:</em> Computes <span class="math inline"><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>.</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><em>in-matrix</em> InMat1,</span>
<span id="cb48-2"><a href="#cb48-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb48-3"><a href="#cb48-3" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb48-4"><a href="#cb48-4" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb48-5"><a href="#cb48-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb48-6"><a href="#cb48-6" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb48-7"><a href="#cb48-7" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb48-8"><a href="#cb48-8" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb48-9"><a href="#cb48-9" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb48-10"><a href="#cb48-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="cb48-11"><a href="#cb48-11" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb48-12"><a href="#cb48-12" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb48-13"><a href="#cb48-13" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb48-14"><a href="#cb48-14" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb48-15"><a href="#cb48-15" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb48-16"><a href="#cb48-16" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb48-17"><a href="#cb48-17" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb48-18"><a href="#cb48-18" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb48-19"><a href="#cb48-19" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb48-20"><a href="#cb48-20" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Effects:</em> Computes <span class="math inline"><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>.</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><em>in-matrix</em> InMat1,</span>
<span id="cb49-2"><a href="#cb49-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb49-3"><a href="#cb49-3" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb49-4"><a href="#cb49-4" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb49-5"><a href="#cb49-5" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb49-6"><a href="#cb49-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb49-7"><a href="#cb49-7" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb49-8"><a href="#cb49-8" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb49-9"><a href="#cb49-9" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb49-10"><a href="#cb49-10" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb49-11"><a href="#cb49-11" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb49-12"><a href="#cb49-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="cb49-13"><a href="#cb49-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb49-14"><a href="#cb49-14" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb49-15"><a href="#cb49-15" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb49-16"><a href="#cb49-16" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb49-17"><a href="#cb49-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb49-18"><a href="#cb49-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> symmetric_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb49-19"><a href="#cb49-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb49-20"><a href="#cb49-20" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb49-21"><a href="#cb49-21" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb49-22"><a href="#cb49-22" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb49-23"><a href="#cb49-23" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb49-24"><a href="#cb49-24" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em> = <em>E</em> + <em>A</em><em>B</em><sup><em>T</em></sup> + <em>B</em><em>A</em><sup><em>T</em></sup></span>.</p>
<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><em>in-matrix</em> InMat1,</span>
<span id="cb50-2"><a href="#cb50-2" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb50-3"><a href="#cb50-3" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb50-4"><a href="#cb50-4" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb50-5"><a href="#cb50-5" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb50-6"><a href="#cb50-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb50-7"><a href="#cb50-7" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb50-8"><a href="#cb50-8" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb50-9"><a href="#cb50-9" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb50-10"><a href="#cb50-10" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb50-11"><a href="#cb50-11" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span>
<span id="cb50-12"><a href="#cb50-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="cb50-13"><a href="#cb50-13" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat1,</span>
<span id="cb50-14"><a href="#cb50-14" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat2,</span>
<span id="cb50-15"><a href="#cb50-15" aria-hidden="true" tabindex="-1"></a>         <em>in-matrix</em> InMat3,</span>
<span id="cb50-16"><a href="#cb50-16" aria-hidden="true" tabindex="-1"></a>         <em>possibly-packed-out-matrix</em> OutMat,</span>
<span id="cb50-17"><a href="#cb50-17" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> Triangle<span class="op">&gt;</span></span>
<span id="cb50-18"><a href="#cb50-18" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> hermitian_matrix_rank_2k_update<span class="op">(</span></span>
<span id="cb50-19"><a href="#cb50-19" aria-hidden="true" tabindex="-1"></a>  ExecutionPolicy<span class="op">&amp;&amp;</span> exec,</span>
<span id="cb50-20"><a href="#cb50-20" aria-hidden="true" tabindex="-1"></a>  InMat1 A,</span>
<span id="cb50-21"><a href="#cb50-21" aria-hidden="true" tabindex="-1"></a>  InMat2 B,</span>
<span id="cb50-22"><a href="#cb50-22" aria-hidden="true" tabindex="-1"></a>  InMat3 E,</span>
<span id="cb50-23"><a href="#cb50-23" aria-hidden="true" tabindex="-1"></a>  OutMat C,</span>
<span id="cb50-24"><a href="#cb50-24" aria-hidden="true" tabindex="-1"></a>  Triangle t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Effects:</em> Computes <span class="math inline"><em>C</em> = <em>E</em> + <em>A</em><em>B</em><sup><em>H</em></sup> + <em>B</em><em>A</em><sup><em>H</em></sup></span>.</p>
</div>
</div>
</body>
</html>
