<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://restgroup.github.io/rstsr-book/blog</id>
    <title>RSTSR: An n-Dimensional Rust Tensor Toolkit Blog</title>
    <updated>2025-01-25T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://restgroup.github.io/rstsr-book/blog"/>
    <subtitle>RSTSR: An n-Dimensional Rust Tensor Toolkit Blog</subtitle>
    <icon>https://restgroup.github.io/rstsr-book/img/logo-64.ico</icon>
    <entry>
        <title type="html"><![CDATA[RSTSR 2nd Report]]></title>
        <id>https://restgroup.github.io/rstsr-book/blog/rstsr-second-report</id>
        <link href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report"/>
        <updated>2025-01-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[RSTSR 2nd report: understanding and requirements of electronic structure programs from a NumPy+Rust perspective]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="rstsr-2nd-report-understanding-and-requirements-of-electronic-structure-programs-a-numpyrust-perspective">RSTSR 2nd Report: Understanding and Requirements of Electronic Structure Programs: A NumPy+Rust Perspective<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#rstsr-2nd-report-understanding-and-requirements-of-electronic-structure-programs-a-numpyrust-perspective" class="hash-link" aria-label="Direct link to RSTSR 2nd Report: Understanding and Requirements of Electronic Structure Programs: A NumPy+Rust Perspective" title="Direct link to RSTSR 2nd Report: Understanding and Requirements of Electronic Structure Programs: A NumPy+Rust Perspective" translate="no">​</a></h2>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-preface">1. Preface<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#1-preface" class="hash-link" aria-label="Direct link to 1. Preface" title="Direct link to 1. Preface" translate="no">​</a></h2>
<p>Development of electronic structure programs aims to solve or discover scientific problems in chemistry and material structure; but the technical challenges involved are often unrelated to chemistry itself. Electronic structure programs need to take into account both 1) development efficiency and reduced communication cost, and 2) program efficiency and resource control; these are also problems that scientific computing in other disciplines, and even general program development tasks, need to solve.</p>
<p>The Rust language has received good reception in some fields of computer science or its applications. But for scientific computing, Rust rarely has outstanding work; and I believe there is still no consensus on whether Rust is suitable for scientific computing.</p>
<p>The previous <a href="https://github.com/ajz34/showcase_rust_riccsd" target="_blank" rel="noopener noreferrer" class="">showcase_rust_riccsd</a> work, I believe, can show that for the problems electronic structure cares about, represented by MP<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">n</span></span></span></span> and CC, it is possible to achieve a good balance between development efficiency and program efficiency with appropriate tools. To demonstrate this possibility, I developed RSTSR as a tensor computing tool. Limited by my horizons, abilities and energy, this tool may not be ideal; but I hope to use this tool to show my understanding of and expectations for Rust scientific computing programs, and to provide some ideas for the development of tensor tools that satisfy electronic structure.</p>
<p>This document hopes to use a simple Q&amp;A style to show my understanding of electronic structure program development and the program problems it cares about, as well as my understanding of the Rust language. The second half of this document will introduce the development ideas of the RSTSR program.</p>
<p>A good program tool should allow users to escape tedious technical details to a certain extent, and focus on their own goals; this is also the original intention of developing math library tools. RSTSR is strongly influenced by NumPy. It is necessary for us to show how NumPy or similar math library tools are concretely used in electronic structure, where their strengths and weaknesses are, and our ideas for improving these problems.</p>
<p>This document assumes that GPU heterogeneity and MPI-scale parallelism are not considered. Some conclusions may not apply to these two situations.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>This document was transcribed from the original typst report to mdx format by AI. The transcription was performed by Deepseek-v4-flash.<br><strong>This document is an early document and does not reflect the current RSTSR design architecture or usage.</strong><br><strong>This document contains some radical viewpoints. These viewpoints do not reflect the views of other developers of the REST program.</strong></p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-electronic-structure-problems">2. Electronic Structure Problems<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#2-electronic-structure-problems" class="hash-link" aria-label="Direct link to 2. Electronic Structure Problems" title="Direct link to 2. Electronic Structure Problems" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="21-as-a-scientific-computing-problem-what-are-the-characteristics-of-electronic-structure">2.1. As a Scientific Computing Problem, What Are the Characteristics of Electronic Structure?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#21-as-a-scientific-computing-problem-what-are-the-characteristics-of-electronic-structure" class="hash-link" aria-label="Direct link to 2.1. As a Scientific Computing Problem, What Are the Characteristics of Electronic Structure?" title="Direct link to 2.1. As a Scientific Computing Problem, What Are the Characteristics of Electronic Structure?" translate="no">​</a></h3>
<p>First, I need to state that my understanding of electronic structure is not complete. I have never written CISD, Full-CI (MCSCF), DMRG, or PBC, and I do not understand the scientific computing challenges of these branches.</p>
<p>Only program implementation issues are discussed here, not method development.</p>
<p>Focusing on problems like MP2, CC and DFT, electronic structure programs</p>
<ol>
<li class="">are mainly composed of matrix operations or operations and contractions of high-dimensional tensors (generally no more than 4-D, rarely exceeding 6-D);</li>
<li class="">have some problems involving eigenvalue solving or matrix decomposition;</li>
<li class="">have a small number of problems involving nonlinear equation solving (iterative solving of matrix equations).</li>
</ol>
<p>Corresponding to the above 3 problems respectively, some of my views are</p>
<ol>
<li class="">Arbitrary-dimension tensor operations and contractions can be classified into two kinds of problems: broadcasted matrix multiplication and broadcasted elementwise operations. This will be explained in detail later, but here we only need to know that these two kinds of problems are relatively standard problems, which can be solved with simple programs and BLAS.</li>
<li class="">Eigenvalue problems and matrix decomposition are standard problems, which can be solved with Lapack.</li>
<li class="">This is not a standard problem, and chemists need to design algorithms according to their own needs. Of course, some matrix equation solvers have solutions in Matlab or SciPy; but their efficiency may not satisfy us.</li>
</ol>
<p>Therefore, among the above 3 problems, the only one where chemists can truly exert their value is the 3rd kind of problem; the rest are standard problems, which can be implemented by program engineers entirely without chemist participation. Chemists are also not professional at dealing with the 3rd kind of problem, and will very likely need to hand it over entirely to numerical mathematicians.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="22-why-do-chemists-write-electronic-structure-programs">2.2. Why Do Chemists Write Electronic Structure Programs?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#22-why-do-chemists-write-electronic-structure-programs" class="hash-link" aria-label="Direct link to 2.2. Why Do Chemists Write Electronic Structure Programs?" title="Direct link to 2.2. Why Do Chemists Write Electronic Structure Programs?" translate="no">​</a></h3>
<p>The previous answer denied most of chemists' value in writing electronic structure programs. Taking CCSD as an example, apart from DIIS iteration, chemists seem to have no use; after all, for the remaining problems, one just needs to write the program from the formulas. If DIIS was developed by a numerical mathematician, then chemists would not need to do anything.</p>
<p>But chemists still write electronic structure programs, for the following reasons:</p>
<ul>
<li class="">There is no funding or policy support to hire scientific computing programmers. I might think that because we cannot show society and the public that our work has more important value (which may also be the truth), money and resources cannot reasonably tilt toward us. There is no way around this.</li>
<li class="">Method development. Chemists are responsible for improving existing methods. Such improvements are usually about accuracy; they sometimes require chemical intuition, and sometimes are a mathematical structure. New methods may need new program tools; the Davidson diagonalization is believed to have come about this way. Therefore, ideally, chemists also need to be engineers and mathematicians. There are also people who improve efficiency (I think Eshuis of the Furche group improving the RPA algorithm is a typical example), but such work is more like the work of mathematicians, and does not really require chemical participation.</li>
</ul>
<p>But if it is about implementing existing electronic structure methods more efficiently, or in a new program, or writing the gradient properties of existing electronic structure methods, then these have nothing to do with chemistry.</p>
<p>I have also heard more than one person mention that when working with program engineers, they strongly feel that engineers do not understand electronic structure (which produces a certain degree of negative experience). Since I have never worked with engineers, perhaps my following understanding is wrong: in my view, the possible factors causing this communication barrier are</p>
<ul>
<li class="">either the program engineer is limited in ability and cannot correctly understand numerical problems (unrelated to engineers not understanding chemistry);</li>
<li class="">or the chemist did not successfully transform the electronic structure problem into a numerical problem (thus the problem lies with the chemist);</li>
</ul>
<p>Of course, if one person is both a chemist and an engineer, then this communication barrier does not exist.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="23-does-the-early-development-of-the-rest-program-need-chemists">2.3. Does the Early Development of the REST Program Need Chemists?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#23-does-the-early-development-of-the-rest-program-need-chemists" class="hash-link" aria-label="Direct link to 2.3. Does the Early Development of the REST Program Need Chemists?" title="Direct link to 2.3. Does the Early Development of the REST Program Need Chemists?" translate="no">​</a></h3>
<p>In my view, no. The main purpose of the early program is to implement existing algorithms (migrating them from other languages or toolchains into REST), which is not chemistry. But an engineer who can understand the language of chemistry is always good.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-numpy">3. NumPy<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#3-numpy" class="hash-link" aria-label="Direct link to 3. NumPy" title="Direct link to 3. NumPy" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="31-why-do-you-recommend-chemists-to-use-numpy-what-are-its-advantages">3.1. Why Do You Recommend Chemists to Use NumPy? What Are Its Advantages?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#31-why-do-you-recommend-chemists-to-use-numpy-what-are-its-advantages" class="hash-link" aria-label="Direct link to 3.1. Why Do You Recommend Chemists to Use NumPy? What Are Its Advantages?" title="Direct link to 3.1. Why Do You Recommend Chemists to Use NumPy? What Are Its Advantages?" translate="no">​</a></h3>
<p>This is a subjective question. Everyone should have their own opinion on what kind of program tools are suitable for chemists.</p>
<p>The programming needs of chemists should generally fall on method development.</p>
<p>The main reasons I recommend NumPy are as follows:</p>
<ul>
<li class=""><strong>Python, the scripting language.</strong> Scripting languages usually have an interactive running mode (bash has shell, python has jupyter, etc.), which is an advantage compiled languages do not have (or at least not conveniently). <br>
<em>But this does not explain why not use Pytorch, Matlab, Mathematica, JavaScript or Julia.</em></li>
<li class=""><strong>Arbitrary-dimension tensor support and Basic Slicing.</strong> Basic slicing is a means of giving sub-matrices/tensors without copying. This pattern should have started from Fortran, and is not a feature unique to NumPy. <br>
<em>But this does not explain why not use Pytorch, Matlab, Mathematica, JavaScript or Julia.</em></li>
<li class=""><strong>Support for Einsum.</strong> This is of great help for prototype implementation of post-HF methods. <br>
<em>But this does not explain why not use Pytorch, Matlab, Mathematica, JavaScript or Julia.</em></li>
<li class=""><strong>Fast matrix multiplication.</strong> NumPy connects to high-efficiency BLAS functions for matrix multiplication, so if the computational bottleneck is in matrix multiplication, NumPy is generally not too slow. <br>
<em>But this does not explain why not use Pytorch, Matlab, Mathematica, JavaScript or Julia.</em></li>
<li class=""><strong>Relatively complete linear algebra support.</strong> Combined with SciPy, NumPy has solutions for matrix linear algebra, eigenvalue solving, FFT, ODE, extremum problems, etc.<br>
<em>Finally, there are ODE and extremum problems that JavaScript's stdlib does not support, so it is out.</em></li>
</ul>
<p>Among the above 5 factors, the first 3 are decisive factors, all indispensable. But at the same time, you will find that no recommendation reason is unique to NumPy. So it is completely fair to say that recommending NumPy is definitely pushing a personal agenda.</p>
<p>Where NumPy truly has additional advantages over other tools is in</p>
<ul>
<li class=""><strong>Python as a general-purpose language.</strong> This is something Matlab and Mathematica cannot do, and Julia is not good at. JavaScript is more suitable for the frontend.</li>
<li class=""><strong>The Python ecosystem.</strong> A larger ecosystem means that if you encounter any problem, others may have encountered it too, and there are public solutions. PyPI and Conda are also important to the Python ecosystem.</li>
<li class=""><strong>Convenience of installation and a smaller runtime.</strong> This is relative to Pytorch. Runtime means runtime; here we mean that NumPy as a Python library has a relatively small binary size, and has no extra dependencies besides BLAS.</li>
</ul>
<p>These additional advantages are not decisive. Moreover, NumPy also has disadvantages; some disadvantages are fatal.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="32-what-are-numpys-disadvantages">3.2. What Are NumPy's Disadvantages?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#32-what-are-numpys-disadvantages" class="hash-link" aria-label="Direct link to 3.2. What Are NumPy's Disadvantages?" title="Direct link to 3.2. What Are NumPy's Disadvantages?" translate="no">​</a></h3>
<p>From my usage experience,</p>
<ol>
<li class="">
<p><strong>No automatic differentiation.</strong> This is not the most concerning problem for electronic structure programs, but it is indeed one of the most demanded features right now.</p>
</li>
<li class="">
<p><strong>No heterogeneous support.</strong> Using only NumPy, one cannot run on GPU. GPU is indeed one of the important directions of scientific computing in the future.</p>
</li>
<li class="">
<p><strong>Python loops are slow.</strong> This is well known. For many standard matrix operation problems, we indeed may not need Python for loops; but if we encounter a triangular matrix assignment problem like the following (possibly used for tensor symmetrization <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi>t</mi><mrow><mi>j</mi><mi>i</mi></mrow><mrow><mi>b</mi><mi>a</mi></mrow></msubsup><mo>:</mo><mo>=</mo><msubsup><mi>t</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>a</mi><mi>b</mi></mrow></msubsup></mrow><annotation encoding="application/x-tex">t_{ji}^{ba} := t_{ij}^{ab}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2439em;vertical-align:-0.3948em"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8491em"><span style="top:-2.4413em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">i</span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ba</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3948em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">:=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.2439em;vertical-align:-0.3948em"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8491em"><span style="top:-2.4413em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3948em"><span></span></span></span></span></span></span></span></span></span>):</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> j </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> a </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nvir</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> b </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                t2</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">j</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> t2</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> j</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<p>There is no suitable NumPy function for this type of operation, which produces quite serious computational efficiency problems. Although it has solutions (Numba jit), it is always not very convenient.</p>
</li>
<li class="">
<p><strong>Python iterators are hard to parallelize with threads.</strong> But Python parallelism is only suitable at the process level (multiprocessing), not at the thread level. The above is also an example: the above <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi>t</mi><mrow><mi>j</mi><mi>i</mi></mrow><mrow><mi>b</mi><mi>a</mi></mrow></msubsup><mo>:</mo><mo>=</mo><msubsup><mi>t</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>a</mi><mi>b</mi></mrow></msubsup></mrow><annotation encoding="application/x-tex">t_{ji}^{ba} := t_{ij}^{ab}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2439em;vertical-align:-0.3948em"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8491em"><span style="top:-2.4413em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">i</span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ba</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3948em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">:=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.2439em;vertical-align:-0.3948em"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8491em"><span style="top:-2.4413em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3948em"><span></span></span></span></span></span></span></span></span></span> computation can be parallelized with a double loop over the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mo separator="true">,</mo><mi>j</mi></mrow><annotation encoding="application/x-tex">i, j</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.854em;vertical-align:-0.1944em"></span><span class="mord mathnormal">i</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0572em">j</span></span></span></span> indices. Using fairly standard Python parallel libraries, the effect is a complete mess.</p>
</li>
<li class="">
<p><strong>Numba JIT programming is not native Python.</strong> The above two points can be solved with Numba. Numba is not impossible either, but JIT itself takes time, and Numba syntax is not exactly Python; precompiled JIT is also not impossible, but then what is the difference from using the FFI of a compiled language (like C)? JIT programming is not without thresholds: if input and output types are not clearly written, and parallel is not correctly enabled, Numba's acceleration is not good either.</p>
</li>
<li class="">
<p><strong>Computation on non-contiguous matrices is very slow and not parallelized.</strong> A typical problem is the closed-shell RI-MP2 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><msup><mi>n</mi><mn>4</mn></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(n^4)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0641em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">4</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> energy summation problem. Simplified to a concrete expression, when matrices <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">A</mi></mrow><annotation encoding="application/x-tex">\mathbf{A}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">A</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">B</mi></mrow><annotation encoding="application/x-tex">\mathbf{B}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">B</span></span></span></span> are both c-contiguous or f-contiguous, the operations <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mi>A</mi><mo>−</mo><msup><mi>A</mi><mi>T</mi></msup></mrow><annotation encoding="application/x-tex">2A - A^T</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em"></span><span class="mord">2</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.8413em"></span><span class="mord"><span class="mord mathnormal">A</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8413em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">T</span></span></span></span></span></span></span></span></span></span></span> or <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mo>⊙</mo><msup><mi>B</mi><mi>T</mi></msup></mrow><annotation encoding="application/x-tex">A \odot B^T</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em"></span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">⊙</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.8413em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8413em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">T</span></span></span></span></span></span></span></span></span></span></span> are outrageously slow.<br>
<!-- -->Similar problems also appear when calling SciPy. SciPy is usually friendly to f-contiguous matrices; if the input matrix is c-contiguous, it sometimes performs a very inefficient matrix transpose first.</p>
</li>
<li class="">
<p><strong>Computation on contiguous vectors is not parallelized.</strong> NumPy does optimize operations on contiguous vectors (SIMD vectorization), but this is mostly work from 10 years ago. 10 years ago, on personal computers, single-threaded operations could generally saturate memory bandwidth; but times have changed, and for some problems a single thread can no longer keep up with memory bandwidth speed. It can be considered that as long as the problem is not matrix multiplication or eigenvalue problems, NumPy has some room for efficiency improvement.</p>
</li>
<li class="">
<p><strong>Some function names are quite bad.</strong> For example <code>np.ix_</code>; this may be for historical reasons.</p>
</li>
<li class="">
<p><strong>Memory control is difficult.</strong> This is related to Python's variable lifetimes. Rust can avoid this problem.</p>
</li>
</ol>
<p>Some of the above problems are also problems encountered by Matlab and Mathematica. The Julia language can combine the advantages of both scripting languages and compiled languages; from this perspective it is indeed a tool more suitable for scientific computing; but the development trend and professionalism of the language itself worry me somewhat.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="33-we-are-a-rust-program-why-mention-python-and-numpy">3.3. We Are a Rust Program; Why Mention Python and NumPy?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#33-we-are-a-rust-program-why-mention-python-and-numpy" class="hash-link" aria-label="Direct link to 3.3. We Are a Rust Program; Why Mention Python and NumPy?" title="Direct link to 3.3. We Are a Rust Program; Why Mention Python and NumPy?" translate="no">​</a></h3>
<p>We are not saying NumPy is good or bad. But we are writing Rust programs and need to use some math libraries. Therefore we need a general understanding of what features math libraries generally have.</p>
<p>From the perspective of scientific computing, NumPy may not be the best choice. But there are reasons to choose NumPy as the baseline for discussing math libraries:</p>
<ul>
<li class="">I am more used to NumPy, and the most popular computational chemistry program in the open-source community right now is PySCF (judging by GitHub stars). Of course there is personal preference involved.</li>
<li class="">The Python language that NumPy is based on was not specifically designed for scientific computing. The same is true for C++/Rust in this respect; in contrast are Julia and Fortran. This makes many problems have to be implemented through functions (or operator overloading) rather than through language syntax (e.g., transpose, slicing, matmul, vector solve, inversion).</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-strategies-for-rapidly-developing-electronic-structure-programs">4. Strategies for Rapidly Developing Electronic Structure Programs<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#4-strategies-for-rapidly-developing-electronic-structure-programs" class="hash-link" aria-label="Direct link to 4. Strategies for Rapidly Developing Electronic Structure Programs" title="Direct link to 4. Strategies for Rapidly Developing Electronic Structure Programs" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="41-is-there-a-strategy-for-rapidly-developing-electronic-structure-programs-why-is-rust-not-in-this-strategy">4.1. Is There a Strategy for Rapidly Developing Electronic Structure Programs? Why Is Rust Not in This Strategy?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#41-is-there-a-strategy-for-rapidly-developing-electronic-structure-programs-why-is-rust-not-in-this-strategy" class="hash-link" aria-label="Direct link to 4.1. Is There a Strategy for Rapidly Developing Electronic Structure Programs? Why Is Rust Not in This Strategy?" title="Direct link to 4.1. Is There a Strategy for Rapidly Developing Electronic Structure Programs? Why Is Rust Not in This Strategy?" translate="no">​</a></h3>
<p>As mentioned before, the decisive reasons I recommend NumPy are</p>
<ul>
<li class="">scripting language,</li>
<li class="">arbitrary-dimension matrix or tensor support,</li>
<li class="">Einsum support.</li>
</ul>
<p>Of course NumPy is not the only framework suitable for these three points; but since Rust is not a scripting language (REPL language), I would consider it not suitable for rapid development.</p>
<p>Rust is not without REPL frameworks (the evcxr framework), but in my experience compilation is still rather slow.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="42-is-there-a-strategy-for-rapidly-developing-efficient-electronic-structure-programs">4.2. Is There a Strategy for Rapidly Developing Efficient Electronic Structure Programs?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#42-is-there-a-strategy-for-rapidly-developing-efficient-electronic-structure-programs" class="hash-link" aria-label="Direct link to 4.2. Is There a Strategy for Rapidly Developing Efficient Electronic Structure Programs?" title="Direct link to 4.2. Is There a Strategy for Rapidly Developing Efficient Electronic Structure Programs?" translate="no">​</a></h3>
<p>With the word "efficient" added to this question, the above answer is no longer useful.</p>
<p>The development strategy I have tried in implementing RI-MP2 static polarizability and RI-RHF first-order gradient is
0. Organize the problem into mathematical formulas, avoiding any chemical description as much as possible;</p>
<ol>
<li class="">Implement it once in NumPy using Einstein summation;<!-- -->
<ul>
<li class="">This does not mean it can only be implemented with Einstein summation; it is just that for MP<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">n</span></span></span></span>/CC tasks, Einstein is absolutely convenient; but there are also other specific problems suitable for other methods. What is meant here is to translate your chemical problem into a program using any framework you find convenient, and execute it correctly. You need to consider what algorithm to use and how to optimize the algorithm, but correctness comes first, and you do not need to consider the actual program efficiency now.</li>
</ul>
</li>
<li class="">In NumPy, split all Einstein summations into (in priority order)<!-- -->
<ul>
<li class="">matrix multiplication (matmul, matrix multiplication)</li>
<li class="">vector operations (elementwise)</li>
<li class="">operations like summation (reduction)</li>
<li class="">loop unrolling (for loop)
Finally obtain a Python program completely without einsum.</li>
</ul>
</li>
<li class="">In compiled languages like Rust/C, translate the above logic one by one.</li>
</ol>
<p>Except steps 0 and 1, the above process is fairly mechanical. To put it harshly, AI-assisted programming may actually be able to replace steps 2 and 3. But for computational performance, the programs of steps 2 and 3 are also important.</p>
<p>From my experience, after step 1 is successfully completed, step 2 for problems at the level of RI-CCSD or RI-MP2 static polarizability takes about 0.5–5 days, and step 3 takes about 1–10 days; the exact time depends on work state, work environment and concentration, and has nothing to do with the creative intensity at the time. The most difficult part of this process is generally step 1, that is, whether the chemical problem can be correctly written as a program and executed within the math library framework we are used to. Of course, this varies with the problem.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-the-relationship-between-math-libraries-and-electronic-structure">5. The Relationship between Math Libraries and Electronic Structure<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#5-the-relationship-between-math-libraries-and-electronic-structure" class="hash-link" aria-label="Direct link to 5. The Relationship between Math Libraries and Electronic Structure" title="Direct link to 5. The Relationship between Math Libraries and Electronic Structure" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="51-why-waste-time-developing-math-libraries-isnt-our-goal-to-solve-chemistry-problems">5.1. Why Waste Time Developing Math Libraries? Isn't Our Goal to Solve Chemistry Problems?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#51-why-waste-time-developing-math-libraries-isnt-our-goal-to-solve-chemistry-problems" class="hash-link" aria-label="Direct link to 5.1. Why Waste Time Developing Math Libraries? Isn't Our Goal to Solve Chemistry Problems?" title="Direct link to 5.1. Why Waste Time Developing Math Libraries? Isn't Our Goal to Solve Chemistry Problems?" translate="no">​</a></h3>
<p>I would ask in return: why do we use Rust? What is the purpose of giving up the nice scripting languages? Does this really solve chemistry problems?</p>
<p>If one refuses to answer this question, then all the rest of this document is meaningless to the reader. Some situations that seem to answer the question but actually refuse to answer include:</p>
<ul>
<li class="">Our program has already decided to feature Rust.</li>
<li class="">C++ is the Sekiro of the programming world; Rust is the Genshin Impact of the programming world. Rust is the pinnacle of abstraction.</li>
</ul>
<p>I estimate that about 50% of computational chemistry software develops its own math library or binds to external math libraries; some software may even develop two sets, making code reading and communication difficult:</p>
<ul>
<li class="">Q-Chem has developed multiple math libraries internally, including libblas, libmathtools, <a href="https://github.com/epifanovsky/libtensor" target="_blank" rel="noopener noreferrer" class="">libtensor</a>.</li>
<li class="">PySCF mainly uses the external math libraries NumPy and SciPy, and also uses TBLIS; but it has its own programs for some operators, generally defined in <code>np_helper.c</code>.</li>
<li class="">Psi4 has developed its own math library libmints/matrix; judging only from the occ part of Psi4's code, these libraries are mainly used as BLAS wrappers;</li>
<li class="">MPQC (as a computational chemistry program that has stopped maintenance) cooperated with other groups on <a href="https://github.com/m-a-d-n-e-s-s/madness" target="_blank" rel="noopener noreferrer" class="">MADNESS</a> (which is still actively maintained).</li>
</ul>
<p>I dare not say the reasons for developing math libraries are self-evident, but developing math libraries is indeed the choice of many electronic structure developers.</p>
<p>But there are also many people, especially engineers leaning toward high-performance computing, who probably choose not to use existing math libraries. They may need a more flexible program writing style, using at most low-level programs like BLAS or FFT, without heavily using high-level interfaces.</p>
<p>The significance of math libraries is somewhat subtle. In my view, its purpose is: <strong>balancing development efficiency and program efficiency</strong>.</p>
<ul>
<li class="">For the highest development efficiency, one should generally use scripting languages Python, Matlab, Julia;</li>
<li class="">For the highest program efficiency, one should generally directly call low-level BLAS and hand-write some functions.</li>
</ul>
<p>Therefore, the general requirements for math libraries are</p>
<ul>
<li class="">implement important operators to satisfy general numerical computation needs;</li>
<li class="">for the implemented operators, the implementation efficiency should approach the ideal limit;</li>
<li class="">the code should be simple and intuitive enough, and not easily misused by users.</li>
</ul>
<p>Even though the significance of math libraries is subtle, I still think it is necessary to use math libraries in computational chemistry programs. Different people have different judgments on this matter; so this statement can be seen as my philosophical proposition, not necessarily rational. In my previous implementation of RI-MP2 static polarizability, my workflow was to first draft it with NumPy, then implement it in C; it took about a week in total. The C part was mainly implemented by calling BLAS. But calling BLAS is error-prone: it is easy to make mistakes in writing matrix dimensions and leading dimensions without the program reporting errors; such code is also not intuitive. Therefore, to write efficient and correct code faster, I am motivated to develop math libraries.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="52-implementing-a-math-library-is-too-much-work-can-we-design-a-math-library-with-electronic-structure-specific-features">5.2. Implementing a Math Library Is Too Much Work; Can We Design a Math Library with Electronic-Structure-Specific Features?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#52-implementing-a-math-library-is-too-much-work-can-we-design-a-math-library-with-electronic-structure-specific-features" class="hash-link" aria-label="Direct link to 5.2. Implementing a Math Library Is Too Much Work; Can We Design a Math Library with Electronic-Structure-Specific Features?" title="Direct link to 5.2. Implementing a Math Library Is Too Much Work; Can We Design a Math Library with Electronic-Structure-Specific Features?" translate="no">​</a></h3>
<p>I hold a negative position on this question.</p>
<p>The needs that electronic structure has for math libraries already cover the functionality of most math libraries (represented by NumPy). A math library that satisfies electronic structure needs can generally also satisfy the needs of other disciplines.</p>
<p>The specific requirements electronic structure may have for math library features will be discussed later.</p>
<p>For the difficulty of math library development, I think using an unsuitable or inconvenient framework to develop programs is also a time cost, and developing a framework is also a time cost. It is hard for me to evaluate which one takes more time, but the latter indeed gives people the impression of having done nothing, and of not knowing at which specific step the electronic structure method was not implemented. In fact, other developers besides myself, and non-developer classmates, also cannot endorse developing a math library, because it looks very difficult; and with PyTorch being so powerful now, the marginal benefit of doing this seems lower and lower. Only when the shortcomings of NumPy itself are solved, the advantages of Rust as a newly developed compiled language are endorsed, the developed library is satisfactory in both convenience and performance, and the features are relatively complete, can developing a new math library have positive returns; and even so, it cannot directly compete with PyTorch's features and ecosystem.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="53-why-not-consider-using-pytorchs-rust-binding">5.3. Why Not Consider Using PyTorch's Rust Binding?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#53-why-not-consider-using-pytorchs-rust-binding" class="hash-link" aria-label="Direct link to 5.3. Why Not Consider Using PyTorch's Rust Binding?" title="Direct link to 5.3. Why Not Consider Using PyTorch's Rust Binding?" translate="no">​</a></h3>
<p>PyTorch is almost the best math library framework at present, even without considering its more powerful automatic differentiation. I also deeply respect the author of PyTorch's Rust binding crate <code>tch-rs</code>; this is absolutely not a simple binding, it is itself a very good solution for a Rust math library.</p>
<p>I think the following factors are not necessarily decisive, but combined I tend not to use PyTorch's Rust binding crate <code>tch-rs</code>:</p>
<ul>
<li class="">PyTorch's runtime is too large, and users may have linking problems (CPU-only is somewhat better); it may be difficult to run on some devices; a pure-Rust framework can reduce these dependencies, at least down to only needing BLAS (and CUDA later if GPU support is added). It is better to treat PyTorch as an optional backend rather than binding to this one framework.</li>
<li class="">The crate <code>tch-rs</code> is already quite powerful as a libtorch binding and a native Rust interface; but it is still a foreign library, and we cannot fully expect to smoothly add features to it for electronic structure purposes.</li>
<li class="">Getting data in and out of <code>tch-rs</code> tensors currently seems possible only by copying. Rust's standard containers for data are either <code>Vec&lt;T&gt;</code> or <code>&amp;[T]</code>, and producing or extracting data has no overhead; but <code>tch-rs</code> hands the data completely over to the C++ part, and the Rust part no longer has control over the data, so if you want to perform operations on the data outside <code>tch-rs</code>, there is great overhead.</li>
<li class=""><code>tch-rs</code> does not seem to be actively maintained, but it keeps updating PyTorch versions and dependencies to stay usable (or the library may already be in a completed state and needs no updates). The focus of <code>tch-rs</code> developer (<a href="https://github.com/LaurentMazare" target="_blank" rel="noopener noreferrer" class="">Laurent Mazare</a>) is now the candle library, but candle seems even further from electronic structure.</li>
<li class="">Following the above two reasons. I think the reason the author later developed candle is that PyTorch's operators are not necessarily up-to-date in the LLM era; but writing new operators in the PyTorch backend is not convenient unless done in C++; to keep up with LLM development in a framework different from PyTorch, a new machine learning framework was needed. Of course, this is not our concern, but it means that using <code>tch-rs</code> sacrifices considerable flexibility.</li>
<li class="">It is not impossible on the <code>tch-rs</code> framework, but support for complex floating point numbers is currently basically zero.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="54-why-not-consider-using-other-math-libraries-in-rust">5.4. Why Not Consider Using Other Math Libraries in Rust?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#54-why-not-consider-using-other-math-libraries-in-rust" class="hash-link" aria-label="Direct link to 5.4. Why Not Consider Using Other Math Libraries in Rust?" title="Direct link to 5.4. Why Not Consider Using Other Math Libraries in Rust?" translate="no">​</a></h3>
<p>Other Rust math libraries are not unusable either, but I hope to do better. Also refer to <a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#rstsr-pro" class="">RSTSR Features</a> later.</p>
<p>But I also want to say that when I first started with Rust, my mindset was that others wrote math libraries ten years ago, so we might as well use theirs. I held this attitude for a long time, until I could not conveniently use the ndarray framework to achieve a program efficiency satisfactory to me on the RHF first-order gradient problem; and the RHF first-order gradient problem ideally needs three-dimensional tensor support and indexing support close to basic slicing, and rest_tensors is also not very suitable.</p>
<p>I hope that my mindset in developing a Rust math library is not the <a href="https://en.wikipedia.org/wiki/Not_invented_here" target="_blank" rel="noopener noreferrer" class="">Not Invented Here effect</a>. Therefore, I want to use this document to fully state my understanding of the relationship between math libraries and electronic structure, to determine what exactly we want, and why I am not satisfied with existing tools.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-elec-needs-num">5.5. What Math Library Features Do Electronic Structure Programs Need?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#how-elec-needs-num" class="hash-link" aria-label="Direct link to 5.5. What Math Library Features Do Electronic Structure Programs Need?" title="Direct link to 5.5. What Math Library Features Do Electronic Structure Programs Need?" translate="no">​</a></h3>
<p>We answer this question in reverse. What features do math libraries generally have? Which of them will be used by electronic structure programs?</p>
<p>After the explosion of Python math libraries in 2016–2017 with the popularity of machine learning, starting from 2020 the community formed the <a href="https://data-apis.org/array-api/latest" target="_blank" rel="noopener noreferrer" class="">Python array API standard</a>. Although this standard is not mandatory, NumPy 2.0 enabled it; and this standard helps us understand the expectations and basic requirements of general users and developers for math libraries.</p>
<p>The main content of the Python array API standard is in the <a href="https://data-apis.org/array-api/latest/API_specification/index.html" target="_blank" rel="noopener noreferrer" class="">API specification</a>. The main parts are</p>
<ul>
<li class="">
<p><strong>Array object</strong>: the definition of arbitrary-dimension dense tensors (including 0-D scalars), and basic operations such as addition, subtraction, multiplication and division.</p>
<ul>
<li class="">CCSD computation needs the double excitation tensor <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi>t</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>a</mi><mi>b</mi></mrow></msubsup></mrow><annotation encoding="application/x-tex">t_{ij}^{ab}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2439em;vertical-align:-0.3948em"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8491em"><span style="top:-2.4413em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3948em"><span></span></span></span></span></span></span></span></span></span>; various energy and gradient computations need 3c-2e ERIs like <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Y</mi><mrow><mi>i</mi><mi>a</mi><mo separator="true">,</mo><mi>P</mi></mrow></msub></mrow><annotation encoding="application/x-tex">Y_{ia, P}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.2222em">Y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:-0.2222em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ia</span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span> or their Cholesky decomposition; MP2 gradient computation often needs to store three of the dimensions of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi>t</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>a</mi><mi>b</mi></mrow></msubsup></mrow><annotation encoding="application/x-tex">t_{ij}^{ab}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2439em;vertical-align:-0.3948em"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8491em"><span style="top:-2.4413em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3948em"><span></span></span></span></span></span></span></span></span></span>. Generally speaking, computational chemistry has a rigid need for 3-D tensors, and 4-D tensors are also often needed. Meanwhile, gradients often have three-dimensional tensors like <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi>h</mi><mrow><mi>μ</mi><mi>ν</mi></mrow><mi>t</mi></msubsup><mo>=</mo><mo stretchy="false">⟨</mo><mi>μ</mi><mi mathvariant="normal">∣</mi><mi>t</mi><mi mathvariant="normal">∣</mi><mi>ν</mi><mo stretchy="false">⟩</mo></mrow><annotation encoding="application/x-tex">h_{\mu\nu}^{t} = \langle \mu | t | \nu \rangle</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.1767em;vertical-align:-0.3831em"></span><span class="mord"><span class="mord mathnormal">h</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7936em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">μν</span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">t</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mopen">⟨</span><span class="mord mathnormal">μ</span><span class="mord">∣</span><span class="mord mathnormal">t</span><span class="mord">∣</span><span class="mord mathnormal" style="margin-right:0.0637em">ν</span><span class="mclose">⟩</span></span></span></span> (where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi></mrow><annotation encoding="application/x-tex">t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6151em"></span><span class="mord mathnormal">t</span></span></span></span> represents the three components <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo separator="true">,</mo><mi>y</mi><mo separator="true">,</mo><mi>z</mi></mrow><annotation encoding="application/x-tex">x, y, z</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em"></span><span class="mord mathnormal">x</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0359em">y</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.044em">z</span></span></span></span>); although it can indeed be stored as a Vector of three 2-D matrices, storing it directly as a 3-D tensor is generally more convenient.</li>
</ul>
</li>
<li class="">
<p><strong>Broadcasting</strong>: the broadcast computation of tensors. Its rules are quite complex, but the actual applications are two cases:</p>
<ul>
<li class="">
<p>Direct sum or direct product. In MP2 or CCSD energy computation, one encounters the need for a matrix <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi mathvariant="normal">Δ</mi><mrow><mi>a</mi><mi>b</mi></mrow><mrow><mi>i</mi><mi>j</mi></mrow></msubsup></mrow><annotation encoding="application/x-tex">\Delta_{ab}^{ij}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2439em;vertical-align:-0.3013em"></span><span class="mord"><span class="mord">Δ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.9426em"><span style="top:-2.3987em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span><span style="top:-3.1809em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span></span></span></span> (a 2-D matrix only about the indices <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo separator="true">,</mo><mi>b</mi></mrow><annotation encoding="application/x-tex">a, b</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em"></span><span class="mord mathnormal">a</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">b</span></span></span></span>; the indices <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mo separator="true">,</mo><mi>j</mi></mrow><annotation encoding="application/x-tex">i, j</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.854em;vertical-align:-0.1944em"></span><span class="mord mathnormal">i</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0572em">j</span></span></span></span> are generally used in the outer loop), which needs to be computed by:</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">d_ab </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> e_occ</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> e_occ</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">j</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> e_virt</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> e_virt</span><span class="token punctuation" style="color:#393A34">[</span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<p>This is a standard direct sum computation. It uses both broadcasting and the basic indexing trick of adding a dimension (unsqueeze / newaxis).</p>
</li>
<li class="">
<p>Operations of matrices with different dimensions. This is the original purpose of broadcasting, not used much in chemistry; but for the cases where it can be used, broadcasting is very convenient. For example, handling the multiplication of gradient matrices and density matrices:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi mathvariant="normal">∂</mi><msub><mi>A</mi><mi>t</mi></msub></msub><mi>E</mi><mo>←</mo><mo>−</mo><munder><mo>∑</mo><mi>μ</mi></munder><munder><mo>∑</mo><mrow><mi>ν</mi><mo>∈</mo><mi>A</mi></mrow></munder><msubsup><mi>h</mi><mrow><mi>μ</mi><mi>ν</mi></mrow><mi>t</mi></msubsup><msub><mi>D</mi><mrow><mi>μ</mi><mi>ν</mi></mrow></msub></mrow><annotation encoding="application/x-tex">\partial_{A_t} E \leftarrow - \sum_{\mu} \sum_{\nu \in A} h_{\mu\nu}^{t} D_{\mu\nu}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9445em;vertical-align:-0.2501em"></span><span class="mord"><span class="mord" style="margin-right:0.0556em">∂</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:-0.0556em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">A</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2963em"><span style="top:-2.357em;margin-left:0em;margin-right:0.0714em"><span class="pstrut" style="height:2.5em"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.143em"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2501em"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.0576em">E</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.4361em;vertical-align:-1.3861em"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.9em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">μ</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3861em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8557em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">ν</span><span class="mrel mtight">∈</span><span class="mord mathnormal mtight">A</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3217em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal">h</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8436em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">μν</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">t</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0278em">D</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0278em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">μν</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span></span>
<p>Letting the variable <code>slc</code> be the set of basis functions on atom <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal">A</span></span></span></span> (we are now discussing programs based on atomic orbitals),</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">de</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">atom</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">deriv_h</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> slc</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> rdm1</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> slc</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">sum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">axis</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>The above computation uses elementwise multiplication of a 3-D and a 2-D matrix, which is broadcasting multiplication.</p>
</li>
</ul>
</li>
<li class="">
<p><strong>Creation Functions</strong>: tensor creation functions. Empty tensors, zero tensors, identity matrices.</p>
</li>
<li class="">
<p><strong>Data Types</strong>: this is not a concrete function, but requires the tensor library to at least handle 8–64 bit integers and unsigned integers, 32–64 bit floating point numbers and complex floating point numbers, and boolean types.</p>
</li>
<li class="">
<p><strong>Element-wise Functions</strong>: operation functions. This includes common functions like abs, sin, log, greater, floor, isnan. Actually many functions are not used in chemistry, but they are still needed to handle the needs of methods like Laplace-Transform for these functions. Determining electron occupation numbers often requires magnitude comparisons.</p>
</li>
<li class="">
<p><strong>Indexing</strong>: arbitrary-dimension indexing, generally referring to NumPy's basic indexing, but the Python array API standard also requires boolean tensor indexing. Computational chemistry has needs for both basic indexing and boolean tensor indexing (or similar index-list indexing):</p>
<ul>
<li class="">
<p>In the two code cases of broadcasting, the direct sum computation of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi mathvariant="normal">Δ</mi><mrow><mi>a</mi><mi>b</mi></mrow><mrow><mi>i</mi><mi>j</mi></mrow></msubsup></mrow><annotation encoding="application/x-tex">\Delta_{ab}^{ij}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2439em;vertical-align:-0.3013em"></span><span class="mord"><span class="mord">Δ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.9426em"><span style="top:-2.3987em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span><span style="top:-3.1809em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span></span></span></span> needs newaxis indexing (adding a dimension via indexing); the computation of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi mathvariant="normal">∂</mi><msub><mi>A</mi><mi>t</mi></msub></msub><mi>E</mi></mrow><annotation encoding="application/x-tex">\partial_{A_t} E</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9445em;vertical-align:-0.2501em"></span><span class="mord"><span class="mord" style="margin-right:0.0556em">∂</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:-0.0556em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">A</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2963em"><span style="top:-2.357em;margin-left:0em;margin-right:0.0714em"><span class="pstrut" style="height:2.5em"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.143em"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2501em"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.0576em">E</span></span></span></span> is standard indexing that extracts part of the contiguous atomic orbitals.</p>
</li>
<li class="">
<p>Some special frozen orbital, or CAS, or MOM orbital selections are implemented by indexing with a list of indices. Suppose we want to obtain the [1, 2, 3, 5, 6] orbitals of the system,</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">frz_orbs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">6</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">frz_coeff </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mo_coeff</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> frz_orbs</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
</li>
</ul>
</li>
<li class="">
<p><strong>Linear Algebra Functions</strong>: matrix multiplication, matrix transpose, tensor contraction, vector inner product. We generally use the first two, and the importance of the first two is self-evident; tensor contraction is implemented by tensordot, which is also a frequently used feature, but at the cost of code readability or convenience it can be replaced by matrix multiplication.</p>
</li>
<li class="">
<p><strong>Manipulation Functions</strong>: common functions include reshape for changing shape, permute_dims (transpose) for tensor transposition, and stack and concat for stacking or concatenating matrices. reshape is a very commonly used and important function.</p>
</li>
<li class="">
<p><strong>Searching Functions</strong>: argmax/argmin, nonzero, where. We do not use these functions much.</p>
</li>
<li class="">
<p><strong>Set Functions</strong>: convert tensors to sets (set, in the programming context). We do not use these functions.</p>
</li>
<li class="">
<p><strong>Sorting Functions</strong>: sorting functions. Not used much in electronic structure, but may be used in the future.</p>
</li>
<li class="">
<p><strong>Statistical Functions</strong>: max/min, sum, prod, std, etc. We need to use sum often.</p>
</li>
</ul>
<p>In summary, <strong>electronic structure has comprehensive needs for math libraries</strong>. Except the three categories Searching, Set, Sorting, we need all the rest.</p>
<p>In addition, there are many features that math libraries may not have, but are of important use in computational chemistry:</p>
<ul>
<li class="">
<p><strong>Matrix decomposition.</strong> This is part of Lapack; its significance is self-evident.</p>
</li>
<li class="">
<p><strong>Special operators or einsum.</strong> einsum is not within the scope required by the Python array API standard, but it is of great help to electronic structure. Many DFT computations are inefficient under standard operators; one either needs to implement a powerful einsum, or manually implement these operators (like the current rest_tensors and PySCF).</p>
</li>
<li class="">
<p><strong>Nonlinear matrix equations.</strong> This refers to solving <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi mathvariant="bold">x</mi><mo stretchy="false">)</mo><mo>−</mo><mi mathvariant="bold">b</mi><mo>=</mo><mn mathvariant="bold">0</mn></mrow><annotation encoding="application/x-tex">f(\mathbf{x}) - \mathbf{b} = \mathbf{0}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.1076em">f</span><span class="mopen">(</span><span class="mord mathbf">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6944em"></span><span class="mord mathbf">b</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord mathbf">0</span></span></span></span>; but note that although <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi mathvariant="bold">x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f(\mathbf{x})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.1076em">f</span><span class="mopen">(</span><span class="mord mathbf">x</span><span class="mclose">)</span></span></span></span> can be written as <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">A</mi><mi mathvariant="bold">x</mi></mrow><annotation encoding="application/x-tex">\mathbf{A} \mathbf{x}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">Ax</span></span></span></span>, due to computational difficulty or excessive storage, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">A</mi></mrow><annotation encoding="application/x-tex">\mathbf{A}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">A</span></span></span></span> will not be directly computed, so <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">x</mi></mrow><annotation encoding="application/x-tex">\mathbf{x}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4444em"></span><span class="mord mathbf">x</span></span></span></span> needs to be implemented by solving equations. The typical problem of this kind is the CP-KS equation, and of course also similar Casida equations or wave function stability analysis. These problems may be problems that SciPy cares about, or may require us to implement the algorithms ourselves.</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-understanding-of-performance-understanding-of-rust">6. Understanding of Performance, Understanding of Rust<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#6-understanding-of-performance-understanding-of-rust" class="hash-link" aria-label="Direct link to 6. Understanding of Performance, Understanding of Rust" title="Direct link to 6. Understanding of Performance, Understanding of Rust" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="61-how-do-you-view-rust">6.1. How Do You View Rust?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#61-how-do-you-view-rust" class="hash-link" aria-label="Direct link to 6.1. How Do You View Rust?" title="Direct link to 6.1. How Do You View Rust?" translate="no">​</a></h3>
<p>Rust is a new language; even general programmers have less exposure to it and find it difficult to learn, not to mention computational chemistry programmers. Migrating the workflow to Rust generally means that C++, Fortran, Python or Matlab cannot satisfy us in some situation, and this dissatisfaction is not easily compromised:</p>
<ul>
<li class="">Matlab is commercial software and not a general-purpose language;</li>
<li class="">Python has defects in performance and parallelism, and memory control is difficult; Python's MPI is not convenient;</li>
<li class="">C++ is not impossible, but it is not easy to write code that correctly conforms to program standards, and we currently do not have senior architects; C++ project organization is not as convenient as Python's PyPI or Rust's Cargo; C++ templates and macros are too flexible, easily producing hidden compilation problems, and IDEs cannot correctly recognize some syntax.</li>
<li class="">C is not a high-level language, and problems like compiling correctly but failing at runtime, segmentfaults, etc., easily occur;</li>
<li class="">Fortran has similar problems to C in its low-level parts, and as a high-level language it is not as good as C++.</li>
</ul>
<p>Rust indeed solves most of the above problems well; there are still some regrets in actual experience, but most regrets are not decisive.</p>
<p>One of the important reasons to choose Rust, I believe, is its higher performance. The most important reason for abandoning Python in favor of Rust is generally performance; the secondary reason is that Python's overly flexible program framework makes it easy for novice programmers to write code that does not conform to program standards, polluting the codebase. Therefore, in my view, for people who use Rust and abandon Python (for me, as someone who moved out of the comfort zone of the Python workflow to Rust), <strong>performance is non-negotiable</strong>, at least one cannot make great concessions in performance for higher development efficiency. Otherwise why not use Python.</p>
<p>I did try to write the Rust math library RSTSR. One of the important factors is the hope to advance the development efficiency of electronic structure programs in Rust. But this is advancing development efficiency based as much as possible on fast program performance, not the other way around.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="62-how-to-evaluate-and-improve-computational-performance">6.2. How to Evaluate and Improve Computational Performance?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#62-how-to-evaluate-and-improve-computational-performance" class="hash-link" aria-label="Direct link to 6.2. How to Evaluate and Improve Computational Performance?" title="Direct link to 6.2. How to Evaluate and Improve Computational Performance?" translate="no">​</a></h3>
<p>Although Rust is said to have higher performance, it must be pointed out that</p>
<ol>
<li class="">C/C++/Julia, as compiled languages, generally also have higher performance.</li>
<li class="">Language is not the only factor determining performance. Even with the same algorithm, the way the program is written (techniques) also determines program performance.</li>
</ol>
<p>To avoid falling into agnosticism (making the discussion ineffective) when discussing program performance, it is necessary to state here that program performance has its evaluation strategy. This generally has nothing to do with Rust; as long as it is a language with a relatively powerful compilation backend (like GNU, LLVM), the discussion here applies.</p>
<p>Most of the understanding here took shape from implementing the CNN Winograd algorithm. The CNN Winograd algorithm is a very interesting example: it is both compute-intensive and requires heavy bandwidth usage; and to improve computational efficiency, assembly language (or instruction set functions close to assembly) is needed. The content discussed below is reflected in <a href="https://ajz34.readthedocs.io/zh-cn/latest/ML_Notes/winograd6x3/cnn_winograd_l2.html" target="_blank" rel="noopener noreferrer" class="">this document</a>.</p>
<ol>
<li class="">
<p><strong>The premise of pursuing performance is an efficient algorithm.</strong> Algorithm has two meanings:</p>
<ul>
<li class="">
<p><strong>Algorithm complexity.</strong> A typical example is the MP2 4c-2e AO2MO problem:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msubsup><mi>g</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>a</mi><mi>b</mi></mrow></msubsup><mo>=</mo><munder><mo>∑</mo><mrow><mi>μ</mi><mi>ν</mi><mi>κ</mi><mi>λ</mi></mrow></munder><msubsup><mi>C</mi><mi>i</mi><mi>μ</mi></msubsup><msubsup><mi>C</mi><mi>a</mi><mi>ν</mi></msubsup><msubsup><mi>g</mi><mrow><mi>μ</mi><mi>ν</mi></mrow><mrow><mi>κ</mi><mi>λ</mi></mrow></msubsup><msubsup><mi>C</mi><mi>κ</mi><mi>j</mi></msubsup><msubsup><mi>C</mi><mi>λ</mi><mi>b</mi></msubsup></mrow><annotation encoding="application/x-tex">g_{ij}^{ab} = \sum_{\mu\nu\kappa\lambda} C_i^{\mu} C_a^{\nu} g_{\mu\nu}^{\kappa\lambda} C_{\kappa}^{j} C_{\lambda}^{b}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2822em;vertical-align:-0.3831em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em">g</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.4882em;vertical-align:-1.4382em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8479em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">μν</span><span class="mord mathnormal mtight">κλ</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4382em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7823em"><span style="top:-2.4231em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span><span style="top:-3.1809em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">μ</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2769em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7144em"><span style="top:-2.453em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">a</span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">ν</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em">g</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">μν</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">κλ</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8747em"><span style="top:-2.453em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">κ</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">λ</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">b</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span></span></span></span></span>
<p>If no optimization is done and the above formula is computed directly, an 8-fold loop would be written (because there are 8 indices <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mi>j</mi><mi>a</mi><mi>b</mi><mi>μ</mi><mi>ν</mi><mi>κ</mi><mi>λ</mi></mrow><annotation encoding="application/x-tex">i j a b \mu\nu\kappa\lambda</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em"></span><span class="mord mathnormal" style="margin-right:0.0572em">ij</span><span class="mord mathnormal">ab</span><span class="mord mathnormal" style="margin-right:0.0637em">μν</span><span class="mord mathnormal">κλ</span></span></span></span>), and each iteration does 4 multiplications and 1 addition, so the FLOPs of the above formula is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>5</mn><msubsup><mi>n</mi><mtext>occ</mtext><mn>2</mn></msubsup><msubsup><mi>n</mi><mtext>vir</mtext><mn>2</mn></msubsup><msubsup><mi>n</mi><mtext>basis</mtext><mn>4</mn></msubsup><mo>∼</mo><mi>O</mi><mo stretchy="false">(</mo><msup><mi>N</mi><mn>8</mn></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">5 n_{\text{occ}}^2 n_{\text{vir}}^2 n_{\text{basis}}^4 \sim O(N^8)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0972em;vertical-align:-0.2831em"></span><span class="mord">5</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">occ</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.4355em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">vir</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2645em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.4169em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">basis</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">4</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2831em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">∼</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.0641em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.109em">N</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">8</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> (i.e., 8th-power complexity). But in fact, without any approximation to the above formula, the same result with no error can be obtained with less computation:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msubsup><mi>g</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>a</mi><mi>b</mi></mrow></msubsup><mo>=</mo><munder><mo>∑</mo><mi>λ</mi></munder><msubsup><mi>C</mi><mi>λ</mi><mi>b</mi></msubsup><munder><mo>∑</mo><mi>ν</mi></munder><msubsup><mi>C</mi><mi>a</mi><mi>ν</mi></msubsup><munder><mo>∑</mo><mi>κ</mi></munder><msubsup><mi>C</mi><mi>κ</mi><mi>j</mi></msubsup><munder><mo>∑</mo><mi>μ</mi></munder><msubsup><mi>C</mi><mi>i</mi><mi>μ</mi></msubsup><msubsup><mi>g</mi><mrow><mi>μ</mi><mi>ν</mi></mrow><mrow><mi>κ</mi><mi>λ</mi></mrow></msubsup></mrow><annotation encoding="application/x-tex">g_{ij}^{ab} = \sum_{\lambda} C_{\lambda}^{b} \sum_{\nu} C_{a}^{\nu} \sum_{\kappa} C_{\kappa}^{j} \sum_{\mu} C_{i}^{\mu} g_{\mu\nu}^{\kappa\lambda}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2822em;vertical-align:-0.3831em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em">g</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.4361em;vertical-align:-1.3861em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8479em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">λ</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">λ</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">b</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.9em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">ν</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.25em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7144em"><span style="top:-2.453em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">ν</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.9em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">κ</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.25em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8747em"><span style="top:-2.453em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">κ</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.9em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">μ</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3861em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7823em"><span style="top:-2.4231em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span style="top:-3.1809em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">μ</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2769em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em">g</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">μν</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">κλ</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span></span></span></span></span>
<p>This requires only 4 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><msup><mi>N</mi><mn>5</mn></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(N^5)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0641em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.109em">N</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">5</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> operations (i.e., 5th-power complexity), greatly simplifying the computation time.</p>
</li>
<li class="">
<p><strong>FLOPs, the floating point operation count.</strong> A simple example: for square matrices <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">A</mi><mo separator="true">,</mo><mi mathvariant="bold">B</mi><mo separator="true">,</mo><mi mathvariant="bold">C</mi></mrow><annotation encoding="application/x-tex">\mathbf{A}, \mathbf{B}, \mathbf{C}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8805em;vertical-align:-0.1944em"></span><span class="mord mathbf">A</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathbf">B</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathbf">C</span></span></span></span> of length <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">n</span></span></span></span>,</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="bold">A</mi><mi mathvariant="bold">C</mi><mo>+</mo><mi mathvariant="bold">B</mi><mi mathvariant="bold">C</mi></mrow><annotation encoding="application/x-tex">\mathbf{A}\mathbf{C} + \mathbf{B}\mathbf{C}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7694em;vertical-align:-0.0833em"></span><span class="mord mathbf">AC</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">BC</span></span></span></span></span>
<p>The FLOPs of this expression is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>4</mn><msup><mi>n</mi><mn>3</mn></msup></mrow><annotation encoding="application/x-tex">4 n^3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141em"></span><span class="mord">4</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span></span></span></span>. But if we combine like terms to get <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi mathvariant="bold">A</mi><mo>+</mo><mi mathvariant="bold">B</mi><mo stretchy="false">)</mo><mi mathvariant="bold">C</mi></mrow><annotation encoding="application/x-tex">(\mathbf{A} + \mathbf{B})\mathbf{C}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mopen">(</span><span class="mord mathbf">A</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathbf">B</span><span class="mclose">)</span><span class="mord mathbf">C</span></span></span></span>, the computation can be halved to <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><msup><mi>n</mi><mn>3</mn></msup></mrow><annotation encoding="application/x-tex">2 n^3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141em"></span><span class="mord">2</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span></span></span></span>. It does not reduce the complexity below cubic, but the performance improvement is still great. This looks like a very simple conclusion, but this method is of great help when dealing with the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><msubsup><mi>n</mi><mtext>occ</mtext><mn>3</mn></msubsup><msubsup><mi>n</mi><mtext>vir</mtext><mn>3</mn></msubsup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(n_{\text{occ}}^3 n_{\text{vir}}^3)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0786em;vertical-align:-0.2645em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">occ</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.4355em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">vir</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2645em"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> terms of RI-CCSD. There is also a class of problems that can reduce computation using symmetry, such as RI-JK integrals, RI-MP2 energy summation, the pp-Ladder term computation of CCSD, etc.</p>
</li>
</ul>
<p>The above discussions do not involve concrete programs or concrete code techniques, but they are the most critical performance improvement factors. <strong>Before using code techniques to accelerate a program, one should as much as possible explore the possibility of improving the algorithm and the FLOPs.</strong></p>
</li>
<li class="">
<p><strong>Determine the FLOPs or bandwidth usage.</strong> Most electronic structure problems, especially those not exploiting sparsity and locality, can have their FLOPs given strictly. This does not mean computing exactly correctly, but at least estimating without deviating more than 10%.<br>
<!-- -->Taking the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><msubsup><mi>n</mi><mtext>occ</mtext><mn>3</mn></msubsup><msubsup><mi>n</mi><mtext>vir</mtext><mn>3</mn></msubsup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(n_{\text{occ}}^3 n_{\text{vir}}^3)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0786em;vertical-align:-0.2645em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">occ</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.4355em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">vir</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2645em"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> terms of RI-CCSD as an example,</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mtable rowspacing="0.25em" columnalign="right left" columnspacing="0em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msubsup><mi>I</mi><mrow><mi>k</mi><mi>l</mi><mi>d</mi><mi>c</mi></mrow><mrow><mo stretchy="false">(</mo><mn>1</mn><mo stretchy="false">)</mo></mrow></msubsup></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mi>P</mi></munder><msubsup><mi>B</mi><mrow><mi>k</mi><mi>d</mi></mrow><mi>P</mi></msubsup><msubsup><mi>B</mi><mrow><mi>l</mi><mi>c</mi></mrow><mi>P</mi></msubsup></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>a</mi></mrow><mrow><mo stretchy="false">(</mo><mn>2</mn><mo stretchy="false">)</mo></mrow></msubsup></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mrow><mi>l</mi><mi>d</mi></mrow></munder><msubsup><mi>I</mi><mrow><mi>k</mi><mi>l</mi><mi>d</mi><mi>c</mi></mrow><mrow><mo stretchy="false">(</mo><mn>1</mn><mo stretchy="false">)</mo></mrow></msubsup><msubsup><mi>t</mi><mrow><mi>i</mi><mi>l</mi></mrow><mrow><mi>d</mi><mi>a</mi></mrow></msubsup></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>a</mi></mrow><mrow><mo stretchy="false">(</mo><mn>3</mn><mo stretchy="false">)</mo></mrow></msubsup></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mrow><mi>l</mi><mi>d</mi></mrow></munder><msubsup><mi>I</mi><mrow><mi>k</mi><mi>l</mi><mi>d</mi><mi>c</mi></mrow><mrow><mo stretchy="false">(</mo><mn>1</mn><mo stretchy="false">)</mo></mrow></msubsup><msubsup><mi>t</mi><mrow><mi>i</mi><mi>l</mi></mrow><mrow><mi>a</mi><mi>d</mi></mrow></msubsup></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>a</mi></mrow><mrow><mo stretchy="false">(</mo><mn>4</mn><mo stretchy="false">)</mo></mrow></msubsup></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mi>P</mi></munder><mrow><mo fence="true">(</mo><msubsup><mi>B</mi><mrow><mi>i</mi><mi>k</mi></mrow><mi>P</mi></msubsup><mo>+</mo><munder><mo>∑</mo><mi>c</mi></munder><msubsup><mi>B</mi><mrow><mi>d</mi><mi>k</mi></mrow><mi>P</mi></msubsup><msubsup><mi>t</mi><mi>i</mi><mi>d</mi></msubsup><mo fence="true">)</mo></mrow><mrow><mo fence="true">(</mo><msubsup><mi>B</mi><mrow><mi>a</mi><mi>c</mi></mrow><mi>P</mi></msubsup><mo>−</mo><munder><mo>∑</mo><mi>l</mi></munder><msubsup><mi>B</mi><mrow><mi>l</mi><mi>c</mi></mrow><mi>P</mi></msubsup><msubsup><mi>t</mi><mi>l</mi><mi>a</mi></msubsup><mo fence="true">)</mo></mrow></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msubsup><mi>t</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>a</mi><mi>b</mi></mrow></msubsup></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>←</mo><munder><mo>∑</mo><mrow><mi>k</mi><mi>c</mi></mrow></munder><mrow><mo fence="true">(</mo><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>a</mi></mrow><mrow><mo stretchy="false">(</mo><mn>2</mn><mo stretchy="false">)</mo></mrow></msubsup><mo>−</mo><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>a</mi></mrow><mrow><mo stretchy="false">(</mo><mn>3</mn><mo stretchy="false">)</mo></mrow></msubsup><mo>−</mo><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>a</mi></mrow><mrow><mo stretchy="false">(</mo><mn>4</mn><mo stretchy="false">)</mo></mrow></msubsup><mo fence="true">)</mo></mrow><msubsup><mi>t</mi><mrow><mi>j</mi><mi>k</mi></mrow><mrow><mi>c</mi><mi>b</mi></mrow></msubsup></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msubsup><mi>t</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>a</mi><mi>b</mi></mrow></msubsup></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>←</mo><munder><mo>∑</mo><mrow><mi>k</mi><mi>c</mi></mrow></munder><mrow><mo fence="true">(</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>b</mi></mrow><mrow><mo stretchy="false">(</mo><mn>2</mn><mo stretchy="false">)</mo></mrow></msubsup><mo>−</mo><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>b</mi></mrow><mrow><mo stretchy="false">(</mo><mn>4</mn><mo stretchy="false">)</mo></mrow></msubsup><mo fence="true">)</mo></mrow><msubsup><mi>t</mi><mrow><mi>j</mi><mi>k</mi></mrow><mrow><mi>c</mi><mi>a</mi></mrow></msubsup></mrow></mstyle></mtd></mtr></mtable><annotation encoding="application/x-tex">\begin{aligned}
I_{kldc}^{(1)} &amp;= \sum_P B_{kd}^{P} B_{lc}^{P} \\
I_{ikca}^{(2)} &amp;= \sum_{ld} I_{kldc}^{(1)} t_{il}^{da} \\
I_{ikca}^{(3)} &amp;= \sum_{ld} I_{kldc}^{(1)} t_{il}^{ad} \\
I_{ikca}^{(4)} &amp;= \sum_P \left(B_{ik}^{P} + \sum_c B_{dk}^{P} t_i^{d}\right) \left(B_{ac}^{P} - \sum_l B_{lc}^{P} t_l^{a}\right) \\
t_{ij}^{ab} &amp;\leftarrow \sum_{kc} \left(I_{ikca}^{(2)} - I_{ikca}^{(3)} - I_{ikca}^{(4)}\right) t_{jk}^{cb} \\
t_{ij}^{ab} &amp;\leftarrow \sum_{kc} \left(\frac{1}{2} I_{ikcb}^{(2)} - I_{ikcb}^{(4)}\right) t_{jk}^{ca}
\end{aligned}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:16.8049em;vertical-align:-8.1525em"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:8.6525em"><span style="top:-11.3525em"><span class="pstrut" style="height:3.75em"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">c</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">1</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span></span></span><span style="top:-8.7081em"><span class="pstrut" style="height:3.75em"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">2</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span></span></span><span style="top:-6.056em"><span class="pstrut" style="height:3.75em"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">3</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span></span></span><span style="top:-2.7039em"><span class="pstrut" style="height:3.75em"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">4</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span></span></span><span style="top:0.0482em"><span class="pstrut" style="height:3.75em"></span><span class="mord"><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span></span></span><span style="top:3.1003em"><span class="pstrut" style="height:3.75em"></span><span class="mord"><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:8.1525em"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:8.6525em"><span style="top:-11.3525em"><span class="pstrut" style="height:3.75em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8557em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.2943em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8913em"><span style="top:-2.453em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span><span class="mord mathnormal mtight">d</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8913em"><span style="top:-2.453em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span><span class="mord mathnormal mtight">c</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span></span></span><span style="top:-8.7081em"><span class="pstrut" style="height:3.75em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8479em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span><span class="mord mathnormal mtight">d</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">c</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">1</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">a</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span></span></span><span style="top:-6.056em"><span class="pstrut" style="height:3.75em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8479em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span><span class="mord mathnormal mtight">d</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">c</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">1</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">a</span><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span></span></span><span style="top:-2.7039em"><span class="pstrut" style="height:3.75em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8557em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.2943em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="minner"><span class="mopen delimcenter" style="top:0em"><span class="delimsizing size4">(</span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8913em"><span style="top:-2.453em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.9em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.25em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8913em"><span style="top:-2.453em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em"><span class="delimsizing size4">)</span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="minner"><span class="mopen delimcenter" style="top:0em"><span class="delimsizing size4">(</span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8913em"><span style="top:-2.453em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">a</span><span class="mord mathnormal mtight">c</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8479em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8913em"><span style="top:-2.453em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span><span class="mord mathnormal mtight">c</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7144em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">a</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em"><span class="delimsizing size4">)</span></span></span></span></span><span style="top:0.0482em"><span class="pstrut" style="height:3.75em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8479em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span><span class="mord mathnormal mtight">c</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="minner"><span class="mopen delimcenter" style="top:0em"><span class="delimsizing size2">(</span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">2</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">3</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">4</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em"><span class="delimsizing size2">)</span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">b</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span></span></span><span style="top:3.1003em"><span class="pstrut" style="height:3.75em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8479em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span><span class="mord mathnormal mtight">c</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="minner"><span class="mopen delimcenter" style="top:0em"><span class="delimsizing size3">(</span></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em"><span style="top:-2.314em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.677em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">b</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">2</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">b</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">4</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7144em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:8.1525em"><span></span></span></span></span></span></span></span></span></span></span></span>
<p>The above has 6 lines of formulas, but the computation of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi>I</mi><mrow><mi>k</mi><mi>l</mi><mi>d</mi><mi>c</mi></mrow><mrow><mo stretchy="false">(</mo><mn>1</mn><mo stretchy="false">)</mo></mrow></msubsup><mo separator="true">,</mo><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>a</mi></mrow><mrow><mo stretchy="false">(</mo><mn>4</mn><mo stretchy="false">)</mo></mrow></msubsup></mrow><annotation encoding="application/x-tex">I_{kldc}^{(1)}, I_{ikca}^{(4)}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.3461em;vertical-align:-0.3013em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">c</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">1</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">4</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span></span></span></span> is actually negligible; the remaining four lines are each <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><msubsup><mi>n</mi><mtext>occ</mtext><mn>3</mn></msubsup><msubsup><mi>n</mi><mtext>vir</mtext><mn>3</mn></msubsup></mrow><annotation encoding="application/x-tex">2 n_{\text{occ}}^3 n_{\text{vir}}^3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0786em;vertical-align:-0.2645em"></span><span class="mord">2</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">occ</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.4355em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">vir</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2645em"><span></span></span></span></span></span></span></span></span></span> FLOPs, so the total computation of this process is estimated to be <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>8</mn><msubsup><mi>n</mi><mtext>occ</mtext><mn>3</mn></msubsup><msubsup><mi>n</mi><mtext>vir</mtext><mn>3</mn></msubsup></mrow><annotation encoding="application/x-tex">8 n_{\text{occ}}^3 n_{\text{vir}}^3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0786em;vertical-align:-0.2645em"></span><span class="mord">8</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">occ</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.4355em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">vir</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2645em"><span></span></span></span></span></span></span></span></span></span>. Is the rest unimportant? Not very. Looking carefully, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi>I</mi><mrow><mi>k</mi><mi>l</mi><mi>d</mi><mi>c</mi></mrow><mrow><mo stretchy="false">(</mo><mn>1</mn><mo stretchy="false">)</mo></mrow></msubsup></mrow><annotation encoding="application/x-tex">I_{kldc}^{(1)}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.3461em;vertical-align:-0.3013em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">c</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">1</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span></span></span></span> can exploit symmetry, so the FLOPs of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi>I</mi><mrow><mi>k</mi><mi>l</mi><mi>d</mi><mi>c</mi></mrow><mrow><mo stretchy="false">(</mo><mn>1</mn><mo stretchy="false">)</mo></mrow></msubsup><mo separator="true">,</mo><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>a</mi></mrow><mrow><mo stretchy="false">(</mo><mn>4</mn><mo stretchy="false">)</mo></mrow></msubsup></mrow><annotation encoding="application/x-tex">I_{kldc}^{(1)}, I_{ikca}^{(4)}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.3461em;vertical-align:-0.3013em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">c</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">1</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">4</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span></span></span></span> are about <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>3</mn><msubsup><mi>n</mi><mtext>occ</mtext><mn>2</mn></msubsup><msubsup><mi>n</mi><mtext>vir</mtext><mn>2</mn></msubsup><msub><mi>n</mi><mtext>aux</mtext></msub></mrow><annotation encoding="application/x-tex">3 n_{\text{occ}}^2 n_{\text{vir}}^2 n_{\text{aux}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0786em;vertical-align:-0.2645em"></span><span class="mord">3</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">occ</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.4355em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">vir</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2645em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">aux</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span>; its ratio to the computation of the other 4 lines is about <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mi mathvariant="normal">/</mi><msub><mi>n</mi><mtext>vir</mtext></msub></mrow><annotation encoding="application/x-tex">1 / n_{\text{vir}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord">1/</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3175em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">vir</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span>, i.e., when the number of virtual orbitals is greater than 10, the computation of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi>I</mi><mrow><mi>k</mi><mi>l</mi><mi>d</mi><mi>c</mi></mrow><mrow><mo stretchy="false">(</mo><mn>1</mn><mo stretchy="false">)</mo></mrow></msubsup><mo separator="true">,</mo><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>a</mi></mrow><mrow><mo stretchy="false">(</mo><mn>4</mn><mo stretchy="false">)</mo></mrow></msubsup></mrow><annotation encoding="application/x-tex">I_{kldc}^{(1)}, I_{ikca}^{(4)}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.3461em;vertical-align:-0.3013em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">c</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">1</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">4</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span></span></span></span> can be ignored.<br>
<!-- -->The above formula also has some memory bandwidth usage, reflected in the computation of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo fence="true">(</mo><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>a</mi></mrow><mrow><mo stretchy="false">(</mo><mn>2</mn><mo stretchy="false">)</mo></mrow></msubsup><mo>−</mo><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>a</mi></mrow><mrow><mo stretchy="false">(</mo><mn>3</mn><mo stretchy="false">)</mo></mrow></msubsup><mo>−</mo><msubsup><mi>I</mi><mrow><mi>i</mi><mi>k</mi><mi>c</mi><mi>a</mi></mrow><mrow><mo stretchy="false">(</mo><mn>4</mn><mo stretchy="false">)</mo></mrow></msubsup><mo fence="true">)</mo></mrow><annotation encoding="application/x-tex">\left(I_{ikca}^{(2)} - I_{ikca}^{(3)} - I_{ikca}^{(4)}\right)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.8em;vertical-align:-0.65em"></span><span class="minner"><span class="mopen delimcenter" style="top:0em"><span class="delimsizing size2">(</span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">2</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">3</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">ik</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">4</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em"><span class="delimsizing size2">)</span></span></span></span></span></span>. Note that for a computing device with one NUMA node and 16 cores CPU, the typical bandwidth and performance limits are 10 GB/sec (1.2 G doubles/sec) and 1 TFLOP/sec respectively. If the FLOPs and the memory bandwidth demand differ by more than 800 times, then memory bandwidth is not the decisive factor. In the current problem, if <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>n</mi><mtext>occ</mtext></msub><msub><mi>n</mi><mtext>vir</mtext></msub><mo>&gt;</mo><mn>800</mn></mrow><annotation encoding="application/x-tex">n_{\text{occ}} n_{\text{vir}} &gt; 800</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6891em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">occ</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3175em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">vir</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">800</span></span></span></span>, then memory bandwidth no longer matters either. Nevertheless, memory bandwidth analysis is still important in some specific memory-intensive problems (like DFT computation), or in MPI communication.</p>
</li>
<li class="">
<p><strong>Determine the performance limit of the computing device.</strong> Program performance optimization always has an upper bound; this upper bound is not unknowable either. By running the <a href="https://zs3.me/bandwidth" target="_blank" rel="noopener noreferrer" class="">bandwidth64</a> program in parallel, one can generally evaluate the computation and communication efficiency of the L1, L2, L3 caches of the computing device. Intel OneAPI Advisor can also provide valuable data. Generally speaking, current CPUs usually have 70 GFLOP/sec/core (depending on the CPU frequency and the number of AVX channels), and the bandwidth is 16 GB/sec/socket (which should depend on the motherboard and the CPU PCIe). For this part of the information, one can also refer to the previous evaluation document of the HiSilicon Kunpeng device performance. GPU computational performance parameters are generally more transparent than CPU, and can be looked up directly in the official manuals.</p>
</li>
<li class="">
<p><strong>Compare the device limit and the actual program's floating point efficiency FLOP/sec.</strong> Taking the <a href="https://github.com/ajz34/showcase_rust_riccsd" target="_blank" rel="noopener noreferrer" class="">RI-CCSD Rust demonstration case</a> as an example, we can determine that the most time-consuming part averages about 45% utilization of the device performance limit (around 500 GFLOP/sec on a 16-core CPU device). Generally speaking, a program efficiency of 50% of the device performance limit is satisfactory:</p>
<ul>
<li class="">On the one hand, high-performance BLAS achieves only 60%–80% utilization, and further optimization hardly leaves room for improvement;</li>
<li class="">On the other hand, computational chemistry currently has low output value and is usually exploratory research; invalid computation and inefficient usage scenarios are common, so it is acceptable as long as the efficiency is not unbearably low (about 50% extra efficiency loss, i.e., 20% of the device performance limit);</li>
<li class="">Moreover, part of electronic structure tasks are iterative; more iteration steps are themselves performance loss, so pursuing extreme performance also includes pursuing better numerical iteration algorithms.</li>
</ul>
<p>For Python-based programs, considering only the single-node situation, the efficiency is often tolerable in many cases; but there are also many cases where Python and NumPy step on the intolerable low-efficiency red line (this is somewhat why PySCF has so much C code patching).</p>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="63-as-chemistry-programmers-do-we-need-to-manually-tune-performance">6.3. As Chemistry Programmers, Do We Need to Manually Tune Performance?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#63-as-chemistry-programmers-do-we-need-to-manually-tune-performance" class="hash-link" aria-label="Direct link to 6.3. As Chemistry Programmers, Do We Need to Manually Tune Performance?" title="Direct link to 6.3. As Chemistry Programmers, Do We Need to Manually Tune Performance?" translate="no">​</a></h3>
<p>Generally speaking, <strong>we should not</strong>. Chemists, including program engineers working in chemistry, should not waste energy on the showmanship of program optimization, but should let the program return to its essence as a "formula translator". The premise of this statement is that the algorithm has already been designed by chemists and engineers.</p>
<p>Everyone's energy is limited; if everyone can handle their own work well, efficiency will improve quickly. We chemists had better hand over the "formula translator" work entirely to professional numerical program architects, and focus on our own work. But this also means that the "formula translator" itself must be good enough, and professional numerical program architects must be able to do their own work well, for us to use it conveniently.</p>
<p>As a more detailed explanation, the main FLOPs consumption of electronic structure programs is in matrix multiplication; and matrix multiplication is generally provided by BLAS, which we have no ability to manually tune. For the rest, slightly worse performance is acceptable, but like Python and NumPy it is still not very satisfactory. So the room for us to manually tune performance is actually not large; for the three-level caches, pipeline streaming, and prefetching that high-performance computing cares most about, we treat them all as if they did not exist; we write some parallelism when appropriate. This approach is generally fine on CPU, but GPU may need further discussion.</p>
<p>But specifically, this question depends on how "manual performance tuning" is defined, and under what toolchain the tuning is done.</p>
<ul>
<li class="">
<p>One extreme case is that I say I like np.einsum (or equivalent tensor contraction tools in other libraries), and I do not allow more complex expressions. But considering that current tensor contraction tools cannot reach limit efficiency (though it must be admitted that many tensor contraction tools can now achieve ideal efficiency, at least higher than 20% of the limit performance); and some expressions written as Einstein summations may not be suitable for combining like terms, which indeed increases computation time; then manually splitting Einstein summations and combining like terms is necessary.</p>
</li>
<li class="">
<p>A more common but hidden case is that we may encounter non-contiguous dimensions. For example the following problem:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi mathvariant="script">T</mi><mrow><mi>j</mi><mi>b</mi><mi>P</mi></mrow></msub><mo>=</mo><munder><mo>∑</mo><mrow><mi>i</mi><mi>a</mi></mrow></munder><msub><mi>B</mi><mrow><mi>i</mi><mi>a</mi><mi>P</mi></mrow></msub><msub><mi>I</mi><mrow><mi>i</mi><mi>j</mi><mi>a</mi><mi>b</mi></mrow></msub></mrow><annotation encoding="application/x-tex">\mathcal{T}_{jbP} = \sum_{ia} B_{iaP} I_{ijab}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathcal" style="margin-right:0.2542em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.2542em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">b</span><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.3277em;vertical-align:-1.2777em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8723em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ia</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.2777em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ia</span><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span></span>
<p>Although this problem can indeed be implemented by splitting into GEMM (so Einstein summation may also have considerable efficiency):</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># T: jbp, B: iaP, I: ijab</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">T </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nvir</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> naux</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> j </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># can be parallel</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># can be parallel, but with reduce</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        T</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">j</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> I</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> j</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">T @ B</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">T</span><br></div></code></pre></div></div>
<p>But if <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>I</mi><mrow><mi>i</mi><mi>j</mi><mi>a</mi><mi>b</mi></mrow></msub></mrow><annotation encoding="application/x-tex">I_{ijab}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span> is not stored in the order <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mo separator="true">,</mo><mi>j</mi><mo separator="true">,</mo><mi>a</mi><mo separator="true">,</mo><mi>b</mi></mrow><annotation encoding="application/x-tex">i, j, a, b</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em"></span><span class="mord mathnormal">i</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0572em">j</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">a</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">b</span></span></span></span>, but rather as <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>I</mi><mrow><mi>i</mi><mi>a</mi><mi>j</mi><mi>b</mi></mrow></msub></mrow><annotation encoding="application/x-tex">I_{iajb}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">iaj</span><span class="mord mathnormal mtight">b</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span>, then not only is the program more efficient, it can also be done with shorter and clearer code logic:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi mathvariant="script">T</mi><mrow><mi>j</mi><mi>b</mi><mi>P</mi></mrow></msub><mo>=</mo><munder><mo>∑</mo><mrow><mi>i</mi><mi>a</mi></mrow></munder><msub><mi>B</mi><mrow><mi>i</mi><mi>a</mi><mi>P</mi></mrow></msub><msub><mi>I</mi><mrow><mi>i</mi><mi>a</mi><mi>j</mi><mi>b</mi></mrow></msub><mspace width="1em"></mspace><mo>⇒</mo><mspace width="1em"></mspace><msub><mi mathvariant="script">T</mi><mrow><mi>j</mi><mi>b</mi><mo separator="true">,</mo><mi>P</mi></mrow></msub><mo>=</mo><munder><mo>∑</mo><mrow><mi>i</mi><mi>a</mi></mrow></munder><msub><mi>B</mi><mrow><mi>i</mi><mi>a</mi><mo separator="true">,</mo><mi>P</mi></mrow></msub><msub><mi>I</mi><mrow><mi>i</mi><mi>a</mi><mo separator="true">,</mo><mi>j</mi><mi>b</mi></mrow></msub></mrow><annotation encoding="application/x-tex">\mathcal{T}_{jbP} = \sum_{ia} B_{iaP} I_{iajb} \quad \Rightarrow \quad \mathcal{T}_{jb, P} = \sum_{ia} B_{ia, P} I_{ia, jb}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathcal" style="margin-right:0.2542em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.2542em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">b</span><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.3277em;vertical-align:-1.2777em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8723em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ia</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.2777em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ia</span><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">iaj</span><span class="mord mathnormal mtight">b</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:1em"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">⇒</span><span class="mspace" style="margin-right:1em"></span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathcal" style="margin-right:0.2542em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.2542em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">b</span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.3277em;vertical-align:-1.2777em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8723em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ia</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.2777em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ia</span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ia</span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">b</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span></span>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># T: jbp, B: iaP, I: iajb</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">T </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> I</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">reshape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nocc </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> nvir</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">T  @ B</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">reshape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> naux</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">T</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">shape </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nvir</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> naux</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<p>Therefore, before generating the four-dimensional tensor <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">I</mi></mrow><annotation encoding="application/x-tex">\mathbf{I}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">I</span></span></span></span>, we should already consider whether it is more suitable to store it as <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>I</mi><mrow><mi>i</mi><mi>j</mi><mi>a</mi><mi>b</mi></mrow></msub></mrow><annotation encoding="application/x-tex">I_{ijab}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span> or <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>I</mi><mrow><mi>i</mi><mi>a</mi><mi>j</mi><mi>b</mi></mrow></msub></mrow><annotation encoding="application/x-tex">I_{iajb}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em">I</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">iaj</span><span class="mord mathnormal mtight">b</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span>. More extreme problems may not even be expressible with GEMM in any way (an explicit transpose must be performed to convert to a GEMM problem), such as <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi mathvariant="script">T</mi><mrow><mi>P</mi><mi>c</mi><mi>a</mi></mrow></msub><mo>=</mo><msub><mo>∑</mo><mi>b</mi></msub><msub><mi>B</mi><mrow><mi>a</mi><mi>b</mi><mi>P</mi></mrow></msub><msub><mi>f</mi><mrow><mi>b</mi><mi>c</mi></mrow></msub></mrow><annotation encoding="application/x-tex">\mathcal{T}_{Pca} = \sum_b B_{abP} f_{bc}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathcal" style="margin-right:0.2542em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:-0.2542em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">a</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.0497em;vertical-align:-0.2997em"></span><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:0em">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1864em"><span style="top:-2.4003em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2997em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1076em">f</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.1076em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">b</span><span class="mord mathnormal mtight">c</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> — such tensor storage patterns must be avoided.<br>
<!-- -->This type of problem must be considered when writing programs, but it is not something chemists themselves should care about. The "formula translator" itself is only responsible for translating formulas correctly, not for what is the most efficient arrangement of tensor indices. This kind of problem is in the gray zone between chemists and the "formula translator", and needs to be solved by the engineers implementing electronic structure methods.</p>
</li>
<li class="">
<p>Whether the toolchain is mature, efficient, and whether there are problems specific to computational chemistry, are also factors to consider. Math library quality is not high; although this is nominally the responsibility of numerical program architects, chemists may need to lend a hand because there is no one else. Take NumPy as an example here.</p>
<ul>
<li class="">Apart from fast matrix multiplication, NumPy's other operations are inefficient; this caused PySCF to spend considerable effort on DFT-related grid integration problems in C. This is partly NumPy's own problem (it cannot parallelize vector operations well). Early NumPy's matrix multiplication probably had problems too; PySCF's <code>np_helper.c</code> has had to clean up after NumPy quite a lot.</li>
<li class="">NumPy does not provide a GEMM interface itself; for complex matrix <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">C</mi><mo>=</mo><msup><mi mathvariant="bold">A</mi><mo lspace="0em" rspace="0em">†</mo></msup><mi mathvariant="bold">B</mi></mrow><annotation encoding="application/x-tex">\mathbf{C} = \mathbf{A}^{\dagger} \mathbf{B}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">C</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.8491em"></span><span class="mord"><span class="mord mathbf">A</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">†</span></span></span></span></span></span></span></span></span><span class="mord mathbf">B</span></span></span></span> multiplication, one has to call SciPy to solve it (this problem is also not easy to solve in the current RSTSR framework in Rust). So whether to call <code>a.conj() @ b</code> or <code>scipy.linalg.blas.gemm</code>, and whether the matrix fed to SciPy has been transposed to f-contiguous, these fine-grained tricks indeed affect program efficiency to some extent.</li>
<li class="">We often store symmetric matrices as lower triangular matrices (c-contiguous) or upper triangular matrices (f-contiguous); but when actually using them, they need to be expanded to symmetric matrices. This feature is frequently needed in chemistry, and many mainstream math libraries do not support this type of feature well. Expanding such packed matrices is fine to implement in compiled languages, but implementing it in Python is inappropriate; therefore chemists must develop program tools to solve this kind of problem.</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="64-i-cannot-trust-math-library-performance-for-some-problems-should-i-write-my-own-operators">6.4. I Cannot Trust Math Library Performance for Some Problems; Should I Write My Own Operators?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#64-i-cannot-trust-math-library-performance-for-some-problems-should-i-write-my-own-operators" class="hash-link" aria-label="Direct link to 6.4. I Cannot Trust Math Library Performance for Some Problems; Should I Write My Own Operators?" title="Direct link to 6.4. I Cannot Trust Math Library Performance for Some Problems; Should I Write My Own Operators?" translate="no">​</a></h3>
<p>My answer is that at present it is likely still necessary; but this depends on the completeness of the math library.</p>
<p>I do not deny that some math libraries have very bad efficiency on some simple operation problems. Not being able to trust math library performance is completely understandable. I cannot give a firm answer to this question.</p>
<p>But I also think that on many simple standard problems, it is reasonable for math libraries to have good performance. This should not be left to users. Bad math library performance is the math library's problem; as users, we only need to clean up their mess because there is no way around it.</p>
<p>There are also many non-standard problems, especially in machine learning where operator fusion was a hot topic for a while; such problems can usually be reduced to standard problems, but with the necessity of performance optimization or numerical stability optimization (a typical example is softmax). Such problems should have first been solved manually by machine learning deployment engineers; but later PyTorch solved the problems by throwing manpower at operators.</p>
<p>In electronic structure problems, especially the CC/MP<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">n</span></span></span></span> class of problems, everything is matrix multiplication, elementwise multiplication or addition, and summation problems. Such problems are very standard, and there are rarely special computation patterns. Even non-standard problems are usually not FLOPs bottlenecks.</p>
<p>Matrix multiplication should trust BLAS libraries. Even using MKL on AMD CPUs, we can absolutely never write anything faster than BLAS. As a compute-intensive algorithm that is unfriendly to cache access, the concrete algorithm of matrix multiplication is not only complex, but requires very subtle tricks. Besides the complex five-fold loop exploiting the three-level caches (the batch of the loop depends on the L1/L2 cache of the current computing device), it also needs assembly language combined with pipeline streaming and prefetching for the corresponding CPU microarchitecture; this is no longer a problem we should understand. As an introduction (I have not fully understood it either), please refer to the <a href="https://www.cs.utexas.edu/~flame/laff/pfhp/" target="_blank" rel="noopener noreferrer" class="">tutorial of R. van de Geijn</a>, the postdoc advisor of Kazushige Goto (K. Goto) and Devin Matthews.</p>
<p>But many DFT problems, although they can also be implemented with efficient math library functions, may be better without the math library. DFT's performance bottleneck is different from those of HF and post-HF; although two of its steps are GEMM matrix multiplication problems:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>F</mi><mrow><mi>μ</mi><mi>ν</mi></mrow></msub><mo>←</mo><mo>∫</mo><msub><mi>w</mi><mi>μ</mi></msub><mo stretchy="false">(</mo><mi mathvariant="bold">r</mi><mo stretchy="false">)</mo><msub><mi>φ</mi><mi>ν</mi></msub><mo stretchy="false">(</mo><mi mathvariant="bold">r</mi><mo stretchy="false">)</mo><mi mathvariant="normal">d</mi><mi mathvariant="bold">r</mi><mspace width="1em"></mspace><mo>⇒</mo><mspace width="1em"></mspace><msub><mi>F</mi><mrow><mi>μ</mi><mi>ν</mi></mrow></msub><mo>←</mo><munder><mo>∑</mo><mi>g</mi></munder><msub><mi>w</mi><mrow><mi>μ</mi><mi>g</mi></mrow></msub><msub><mi>φ</mi><mrow><mi>ν</mi><mi>g</mi></mrow></msub></mrow><annotation encoding="application/x-tex">F_{\mu\nu} \leftarrow \int w_{\mu}(\mathbf{r}) \varphi_{\nu}(\mathbf{r}) \mathrm{d}\mathbf{r} \quad \Rightarrow \quad F_{\mu\nu} \leftarrow \sum_g w_{\mu g} \varphi_{\nu g}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">F</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">μν</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.2222em;vertical-align:-0.8622em"></span><span class="mop op-symbol large-op" style="margin-right:0.4445em;position:relative;top:-0.0011em">∫</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0269em">w</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0269em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">μ</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathbf">r</span><span class="mclose">)</span><span class="mord"><span class="mord mathnormal">φ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">ν</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathbf">r</span><span class="mclose">)</span><span class="mord mathrm">d</span><span class="mord mathbf">r</span><span class="mspace" style="margin-right:1em"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">⇒</span><span class="mspace" style="margin-right:1em"></span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">F</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">μν</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.4361em;vertical-align:-1.3861em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.9em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3861em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0269em">w</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0269em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em">μg</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">φ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">ν</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span></span>
<p>and the basis transformation problem of orbitals on grid points:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>φ</mi><mi>i</mi></msub><mo stretchy="false">(</mo><mi mathvariant="bold">r</mi><mo stretchy="false">)</mo><mo>=</mo><munder><mo>∑</mo><mi>μ</mi></munder><msub><mi>C</mi><mrow><mi>μ</mi><mi>i</mi></mrow></msub><msub><mi>φ</mi><mi>μ</mi></msub><mo stretchy="false">(</mo><mi mathvariant="bold">r</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\varphi_i(\mathbf{r}) = \sum_{\mu} C_{\mu i} \varphi_{\mu}(\mathbf{r})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal">φ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathbf">r</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.4361em;vertical-align:-1.3861em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.9em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">μ</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3861em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">μ</span><span class="mord mathnormal mtight">i</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">φ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">μ</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathbf">r</span><span class="mclose">)</span></span></span></span></span>
<p>Apart from these two GEMM problems, the other problems are usually not GEMM problems; they are usually bandwidth bottlenecks, but also occupy considerable computation time. Among such problems, some can be efficiently implemented in NumPy with np.einsum, but np.einsum cannot guarantee high efficiency on all problems.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="641-an-operator-case-not-suitable-for-trusting-the-math-library-c_g--sum_i-a_ig-b_ig">6.4.1. An Operator Case Not Suitable for Trusting the Math Library: <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>C</mi><mi>g</mi></msub><mo>=</mo><msub><mo>∑</mo><mi>i</mi></msub><msub><mi>A</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub><msub><mi>B</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub></mrow><annotation encoding="application/x-tex">C_g = \sum_i A_{ig} B_{ig}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.0497em;vertical-align:-0.2997em"></span><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:0em">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.162em"><span style="top:-2.4003em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2997em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal">A</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span><a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#641-an-operator-case-not-suitable-for-trusting-the-math-library-c_g--sum_i-a_ig-b_ig" class="hash-link" aria-label="Direct link to 641-an-operator-case-not-suitable-for-trusting-the-math-library-c_g--sum_i-a_ig-b_ig" title="Direct link to 641-an-operator-case-not-suitable-for-trusting-the-math-library-c_g--sum_i-a_ig-b_ig" translate="no">​</a></h4>
<p>A typical problem is the generation of the SCF density on grid points:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>ρ</mi><mo stretchy="false">(</mo><mi mathvariant="bold">r</mi><mo stretchy="false">)</mo><mo>=</mo><munder><mo>∑</mo><mrow><mi>μ</mi><mi>ν</mi></mrow></munder><msub><mi>D</mi><mrow><mi>μ</mi><mi>ν</mi></mrow></msub><msub><mi>φ</mi><mi>μ</mi></msub><mo stretchy="false">(</mo><mi mathvariant="bold">r</mi><mo stretchy="false">)</mo><msub><mi>φ</mi><mi>ν</mi></msub><mo stretchy="false">(</mo><mi mathvariant="bold">r</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\rho(\mathbf{r}) = \sum_{\mu\nu} D_{\mu\nu} \varphi_{\mu}(\mathbf{r}) \varphi_{\nu}(\mathbf{r})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal">ρ</span><span class="mopen">(</span><span class="mord mathbf">r</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.4361em;vertical-align:-1.3861em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.9em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">μν</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3861em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0278em">D</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0278em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">μν</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">φ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">μ</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathbf">r</span><span class="mclose">)</span><span class="mord"><span class="mord mathnormal">φ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0637em">ν</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathbf">r</span><span class="mclose">)</span></span></span></span></span>
<p>One step of this problem can be reduced to the following numerical problem (based on some algorithms, matrix <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal">A</span></span></span></span> can be equal to matrix <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal" style="margin-right:0.0502em">B</span></span></span></span>, further saving bandwidth):</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>C</mi><mi>g</mi></msub><mo>=</mo><munder><mo>∑</mo><mi>i</mi></munder><msub><mi>A</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub><msub><mi>B</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub></mrow><annotation encoding="application/x-tex">C_g = \sum_i A_{ig} B_{ig}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.3277em;vertical-align:-1.2777em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8723em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.2777em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal">A</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span></span>
<p>This step can be implemented in a standard way in a math library:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>T</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub><mo>=</mo><msub><mi>A</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub><msub><mi>B</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub><mspace width="1em"></mspace><mtext>or</mtext><mspace width="1em"></mspace><mi mathvariant="bold">T</mi><mo>=</mo><mi mathvariant="bold">A</mi><mo>⊙</mo><mi mathvariant="bold">B</mi></mrow><annotation encoding="application/x-tex">T_{ig} = A_{ig} B_{ig} \quad \text{or} \quad \mathbf{T} = \mathbf{A} \odot \mathbf{B}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.9722em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal">A</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:1em"></span><span class="mord text"><span class="mord">or</span></span><span class="mspace" style="margin-right:1em"></span><span class="mord mathbf">T</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.7694em;vertical-align:-0.0833em"></span><span class="mord mathbf">A</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">⊙</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">B</span></span></span></span></span>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>C</mi><mi>g</mi></msub><mo>=</mo><munder><mo>∑</mo><mi>i</mi></munder><msub><mi>T</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub><mspace width="1em"></mspace><mtext>or</mtext><mspace width="1em"></mspace><mi mathvariant="bold">C</mi><mo>=</mo><mtext>sum_row</mtext><mo stretchy="false">(</mo><mi mathvariant="bold">T</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">C_g = \sum_i T_{ig} \quad \text{or} \quad \mathbf{C} = \text{sum\_row}(\mathbf{T})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.3277em;vertical-align:-1.2777em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8723em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.2777em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:1em"></span><span class="mord text"><span class="mord">or</span></span><span class="mspace" style="margin-right:1em"></span><span class="mord mathbf">C</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.06em;vertical-align:-0.31em"></span><span class="mord text"><span class="mord">sum_row</span></span><span class="mopen">(</span><span class="mord mathbf">T</span><span class="mclose">)</span></span></span></span></span>
<p>Written as NumPy code:</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">t </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> b</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">sum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">axis</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>Of course, the above code can also be abbreviated as <code>c = (a * b).sum(axis=0)</code>. Such an algorithm is of course correct, but the cost is generating a temporary tensor <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>T</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub></mrow><annotation encoding="application/x-tex">T_{ig}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span>. The extra memory needed for this temporary tensor is a small matter (because DFT should generally control the number of batched grid points); but the extra write and read of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>T</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub></mrow><annotation encoding="application/x-tex">T_{ig}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span> is a waste of computing resources.</p>
<p>Next, we will use a concrete example to show and compare the computational efficiency of different math libraries and different implementations. For the current problem, the number of orbitals (index <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi></mrow><annotation encoding="application/x-tex">i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6595em"></span><span class="mord mathnormal">i</span></span></span></span>) is set to 1000, and the number of grid points (index <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>g</mi></mrow><annotation encoding="application/x-tex">g</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em"></span><span class="mord mathnormal" style="margin-right:0.0359em">g</span></span></span></span>) is set to 100,000.</p>
<p>We first consider the optimal solution of this code. In Rust, directly computing with a brute-force loop:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> vec_c</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Vec</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">f64</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token macro property" style="color:#36acaa">vec!</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0.0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> ng</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">vec_c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">par_iter_mut</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">enumerate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">for_each</span><span class="token punctuation" style="color:#393A34">(</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token closure-params punctuation" style="color:#393A34">(</span><span class="token closure-params">g</span><span class="token closure-params punctuation" style="color:#393A34">,</span><span class="token closure-params"> c</span><span class="token closure-params punctuation" style="color:#393A34">)</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">ni </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">c </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> vec_a</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> ng </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> g</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> vec_b</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> ng </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> g</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>This computation takes 31 msec. Note that matrices <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">A</mi><mo separator="true">,</mo><mi mathvariant="bold">B</mi></mrow><annotation encoding="application/x-tex">\mathbf{A}, \mathbf{B}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8805em;vertical-align:-0.1944em"></span><span class="mord mathbf">A</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathbf">B</span></span></span></span> each have a memory size of 0.75 GB; traversing these two matrices alone takes about 15 msec; therefore the above implementation reaches at least 50% of the limit bandwidth performance. I cannot yet determine whether there is a faster implementation for the above computation. PySCF has a slightly different algorithm for this problem (the C function <a href="https://github.com/pyscf/pyscf/blob/4e2b9603e3850e9a61118a4bc8c7973c5588c251/pyscf/lib/dft/nr_numint.c#L222-L245" target="_blank" rel="noopener noreferrer" class=""><code>VXC_dcontract_rho</code></a>), which takes 29 msec. I think taking 30 msec as a reference is reasonable.</p>
<p>Do not think that because the fastest for this problem is only 30 msec, it does not need attention. On the one hand, there are quite a few similar processes in DFT computation; on the other hand, if this function is not implemented well, it can take seconds, as will be seen below.</p>
<p>NumPy actually has another tool for this kind of problem: np.einsum:</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">einsum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"ig, ig -&gt; g"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>This function actually has very good performance on the current problem, taking about 36 msec. Moreover, this function runs completely single-threaded, meaning it likely has very strong SIMD optimization but is not parallelized. Due to the characteristics of the current problem, not parallelizing can still achieve good efficiency; but not every problem is like this, and np.einsum will show its disadvantages on other problems.</p>
<p>If we cannot use np.einsum, but use ordinary tensor library logic, then for NumPy:</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># numpy                       #  100 msec in total</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">t </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> b                     </span><span class="token comment" style="color:#999988;font-style:italic">#   79 msec</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">sum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">axis</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">             </span><span class="token comment" style="color:#999988;font-style:italic">#   21 msec</span><br></div></code></pre></div></div>
<p>For Rust's RSTSR:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// RSTSR                      // 127 msec in total</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> t </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">a </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">              </span><span class="token comment" style="color:#999988;font-style:italic">//  97 msec</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">sum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">             </span><span class="token comment" style="color:#999988;font-style:italic">//  31 msec</span><br></div></code></pre></div></div>
<p>For Rust's ndarray:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// ndarray                    // 340 msec in total</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> t </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">a </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">              </span><span class="token comment" style="color:#999988;font-style:italic">// 308 msec</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">sum_axis</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Axis</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">//  21 msec</span><br></div></code></pre></div></div>
<p>For Rust's nalgebra:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// nalgebra                   // 410 msec in total</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> t </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">component_mul</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 343 msec</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">row_sum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">          </span><span class="token comment" style="color:#999988;font-style:italic">//  70 msec</span><br></div></code></pre></div></div>
<p>Although NumPy and RSTSR have considerable efficiency, they are in any case 3–4 times slower than the most efficient code. Therefore, for the current <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>C</mi><mi>g</mi></msub><mo>=</mo><msub><mo>∑</mo><mi>i</mi></msub><msub><mi>A</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub><msub><mi>B</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub></mrow><annotation encoding="application/x-tex">C_g = \sum_i A_{ig} B_{ig}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.0497em;vertical-align:-0.2997em"></span><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:0em">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.162em"><span style="top:-2.4003em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2997em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal">A</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span> problem, to achieve efficiency, it is very likely necessary to implement it in the Einstein summation framework or to hand-write the function, and it cannot be implemented with ordinary matrix multiplication, vector elementwise operations, summation and other basic operators.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="65-which-rust-features-are-unsuitable-for-building-math-libraries">6.5. Which Rust Features Are Unsuitable for Building Math Libraries?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#65-which-rust-features-are-unsuitable-for-building-math-libraries" class="hash-link" aria-label="Direct link to 6.5. Which Rust Features Are Unsuitable for Building Math Libraries?" title="Direct link to 6.5. Which Rust Features Are Unsuitable for Building Math Libraries?" translate="no">​</a></h3>
<ul>
<li class="">
<p><strong>Rust is not a language focused on scientific computing.</strong> Things like transpose, inversion, etc., can neither be replaced by symbols (operators) nor implemented in the language standard library; even complex number operations require external libraries.</p>
</li>
<li class="">
<p><strong>Rust is difficult to implement syntactic sugar with symbols.</strong> Some operator-corresponding traits in Rust are hard-coded; this causes functionality that can be concisely implemented with operators in NumPy to have to be implemented with functions in Rust, greatly increasing syntactic noise. For example,</p>
<ul>
<li class="">
<p><strong>Indexing.</strong> In NumPy, <code>a[1, 2:4, 3:10]</code> can index a three-dimensional tensor to a two-dimensional matrix; this indexing is done through the operator <code>[]</code>. Rust also has the operator <code>[]</code>, but it is done through the Trait <code>Index</code>:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">trait</span><span class="token plain"> </span><span class="token type-definition class-name">Index</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Idx</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">Idx</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token class-name">Sized</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Output</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token class-name">Sized</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Required method</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">index</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Idx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Output</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Its output is <code>&amp;Self::Output</code>, not <code>Self::Output</code>! This means you cannot only return an existing variable, but cannot return some created quantities. We will discuss later that the raw data of an indexed tensor is indeed unchanged, but new shape information and offset are produced; these need new memory space to store. Therefore, the return value of tensor indexing is in any case very difficult to store with a reference type <code>&amp;Self::Output</code>. Thus, for tensor indexing in Rust, unless you just want to take out a value, which can be done with the Trait <code>Index</code> or the equivalent operator <code>[]</code>; otherwise, if you want to index out a sub-tensor, you still have to honestly use a function. In the candle framework this function is <code>.i()</code>, in ndarray it is <code>.slice()</code>; in RSTSR, <code>.i()</code> and <code>.slice()</code> are equivalent.</p>
</li>
<li class="">
<p><strong>Assignment.</strong> C++'s symbol overloading is so powerful that C++ tensor contraction libraries can do wonders with the operator <code>=</code>. But Rust is the other extreme: <code>=</code> only has assignment functionality and cannot be overloaded. This may be designed for Rust's lifetime guarantees, but it is very unfriendly to us scientific computing users. The simplest example is assigning to an indexed tensor:</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">c</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<p>Such code is very intuitive in Python, but Rust does not allow assignment to a statement. In Rust's RSTSR, although this is not unsolvable, it still goes around in circles or adds syntactic noise:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// by assign</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">i_mut</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">..</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">assign</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">i</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">..</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// if c is zeroed before assignment, use add_assign is also valid</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Tensor</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">f64</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">rt</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token function" style="color:#d73a49">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">nao</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nmo</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">device</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">*</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">i_mut</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">..</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">i</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">..</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>Please note that the Trait <code>AddAssign</code> in Rust is overloadable, so the above problem has two solutions. I personally prefer the second one; since it can use the <code>+=</code> symbol, it is more like Python code, but it has a performance cost. The same is true for ndarray.</p>
</li>
<li class="">
<p><strong>Comparison.</strong> Taking the function <code>eq</code> as an example, in the standard library's <code>PartialEq</code>,</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">eq</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> other</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">Rhs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">bool</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>Its return type is hard-coded to boolean. But in NumPy, code like this</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> b  </span><span class="token comment" style="color:#999988;font-style:italic"># returns a tensor of boolean type, not bool itself</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a </span><span class="token keyword" style="color:#00009f">is</span><span class="token plain"> b  </span><span class="token comment" style="color:#999988;font-style:italic"># this returns boolean, but comparing id(a) and id(b)</span><br></div></code></pre></div></div>
<p>especially the first line above, must in Rust be implemented through other functions rather than symbols.</p>
</li>
</ul>
</li>
<li class="">
<p><strong>Rust adds syntactic noise due to its ownership mechanism and error handling mechanism.</strong> This problem is also discussed in the standard library; refer to the <a href="https://github.com/rust-lang/rust/issues/91913#issuecomment-2209392254" target="_blank" rel="noopener noreferrer" class=""><code>Vec::try_with_capacity(_in)</code> issue</a>. This is an indirect rather than direct consequence. Rust's ownership and error handling mechanisms are actually its advantages; but as a library developer, when you start writing functions, you will find that you need to write at least 4 cases. Taking <code>transpose</code> as an example:</p>
<ul>
<li class="">the function <code>into_transpose_f</code> taking values in and out and allowing error handling;</li>
<li class="">the function <code>into_transpose</code> taking values in and out and panicking directly on error;</li>
<li class="">the function <code>transpose_f</code> taking references in, outputting TensorView, and allowing error handling;</li>
<li class="">the function <code>transpose</code> taking references in, outputting TensorView, and panicking directly on error;</li>
</ul>
<p>As a user, generally only <code>transpose</code> is used, same as NumPy. But as a library developer, writing two functions for the two cases of taking references or taking values is something that should be done; you do not know whether users have special requirements for error handling, so it is best to handle the error-handling case (in naming, RSTSR and tch-rs use the <code>_f</code> suffix, and many standard library functions use the <code>try_</code> prefix). And <code>reshape</code> or <code>to_layout</code> functions need to handle two more cases: outputting a Copy on Write type or outputting a value type. So although Rust is very powerful, library developers have to make at least four functions every time they write a feature, many of which are not easy to use with macros; library users also at least need to know which of <code>transpose</code> and <code>into_transpose</code> is the value type and which is the reference type, which is quite laborious.</p>
</li>
<li class="">
<p><strong>Overloading with Traits is not very convenient.</strong> The Rust language itself forbids override and overload. As a non-OOP language, forbidding override is absolute; but as a generic language, overload can be implemented in a roundabout way with generics. Taking the <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/tensor/asarray.rs" target="_blank" rel="noopener noreferrer" class="">asarray function</a> as an example, we can first define the trait</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">trait</span><span class="token plain"> </span><span class="token type-definition class-name">AsArrayAPI</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Sized</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Out</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">asarray</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Out</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>then specialize for various tuple types. For example, if we want to get a one-dimensional tensor from a <code>Vec&lt;T&gt;</code> input, then we specialize for the <code>Vec&lt;T&gt;</code> type (as a 1-element tuple):</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">impl</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token class-name">AsArrayAPI</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token class-name">Vec</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// this allow usage of `asarray(vec)`</span><br></div></code></pre></div></div>
<p>But if we want to directly get a two-dimensional matrix from the input tensor, then we specialize for the 2-element tuple <code>(Vec&lt;T&gt;, Layout&lt;D&gt;)</code>:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">impl</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token class-name">AsArrayAPI</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Vec</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Layout</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// this allow usage of `asarray((vec, layout))`</span><br></div></code></pre></div></div>
<p>As a concrete use case,</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">use</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">rstsr_core</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">prelude</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">use</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">rstsr_openblas</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">DeviceOpenBLAS</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> vec_a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token macro property" style="color:#36acaa">vec!</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0.0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">15</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> vec_b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token macro property" style="color:#36acaa">vec!</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0.0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">15</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> vec_c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token macro property" style="color:#36acaa">vec!</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0.0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">15</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> device_openblas </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">DeviceOpenBLAS</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">default</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// generates 1-D tensor of shape [15] on default device (DeviceFaer)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> tensor_a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">rt</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token function" style="color:#d73a49">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">vec_a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// generates 2-D tensor of shape [3, 5] on default device (DeviceFaer)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> tensor_b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">rt</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token function" style="color:#d73a49">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">vec_b</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// generates 2-D tensor of shape [3, 5] on DeviceOpenBLAS</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> tensor_c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">rt</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token function" style="color:#d73a49">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">vec_c</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">device_openblas</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>This does achieve the goal of overloading with the trait system, and to some extent it is even more flexible than Python (Python does not allow overload on the surface, but allows optional parameters), but there are at least two problems:</p>
<ul>
<li class="">Tuple type parameters must be input, i.e., implementing these functions requires at least two brackets. But for 1-element tuples, the two brackets are redundant, and the VSCode editor will remind you about it. This adds syntactic noise and creates inconsistency in code style; but this is much better than defining three functions <code>asarray_to_1d</code>, <code>asarray_with_shape</code>, <code>asarray_with_shape_and_device</code>. In Python, indexing has the syntactic sugar <code>tensor[(a, b, c)]</code> equivalent to <code>tensor[a, b, c]</code>; I wonder whether Rust has such a plan.</li>
<li class="">Defining an overridable function becomes very complex. It was originally a matter of declaring the function signature a few more times, but now an extra trait is needed. This is an additional burden on API developers. And I have no idea how the API documentation should be written either.</li>
</ul>
</li>
<li class="">
<p><strong>The friendliness of API documentation is questionable.</strong> This is a rather subjective judgment. API documentation is not necessarily well done in any language or any framework. We can see quite good documentation for many Python or C++ libraries, but there is also a lot of manual effort in them. Cargo doc gives us little room to intervene; it guarantees the lower bound of API documentation, but also constrains its upper bound, and may not be suitable for large projects.</p>
</li>
<li class="">
<p><strong>The trait system still has room for improvement.</strong> Rust's trait system is easier to write in a standardized way than C++, solving problems before compilation; this is the benefit of Rust's trait system. But the downside is that there are many restrictions. As an example, when implementing the <code>abs</code> absolute value function, we notice that <code>num::Signed</code> and <code>num::complex::ComplexFloat</code> have two <code>abs</code> implementations. As a math library, we need the <code>abs</code> function for integer types (only implementing <code>Signed</code>), for floating point types (implementing both <code>Signed</code> and <code>ComplexFloat</code>), for complex floating point types (only implementing <code>ComplexFloat</code>), and perhaps also for unsigned integer types (only implementing <code>Unsigned</code>). Although Rust allows you to do this:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">impl</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token class-name">DeviceAbsAPI</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token class-name">DeviceCpuSerial</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"> </span><span class="token class-name">T</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Signed</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>But if you also want to implement <code>ComplexFloat</code> at the same time:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">impl</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token class-name">DeviceAbsAPI</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token class-name">DeviceCpuSerial</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"> </span><span class="token class-name">T</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">ComplexFloat</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Rust will tell you there is a conflict implementation. First, because floating point types implement both <code>Signed</code> and <code>ComplexFloat</code>, there is indeed an implementation conflict. Second, you will find that floating point numbers cannot naturally be <code>Unsigned</code>, so I should be able to implement for <code>Unsigned</code>, right? But this is also not allowed, because Rust does not know which downstream user, on which day, for what ulterior purpose, created a type <code>myf64</code> and implemented both <code>Unsigned</code> and <code>Signed</code> for the <code>myf64</code> type, so that your library really has a conflict implementation. Therefore, there are now three strategies for implementing the <code>abs</code> absolute value function:</p>
<ul>
<li class="">directly specialize for concrete types, without using where clauses;</li>
<li class="">declare two traits (<code>DeviceRealAbsAPI</code>, <code>DeviceComplexAbsAPI</code>), both implementing the <code>abs</code> function;</li>
<li class="">create a new trait of your own, unifying the usage of the abs function.</li>
</ul>
<p>RSTSR currently adopts the 2nd strategy; but I can hardly say this is a good approach, because it either splits floating point types from complex floating point types, or splits integer types from floating point types. I believe this is also the perplexing problem of the crate <code>num</code> (discussed in <a href="https://github.com/rust-num/num-traits/issues/64" target="_blank" rel="noopener noreferrer" class="">issue #64</a>).<br>
<!-- -->The 3rd strategy is actually not impossible, but it has another problem: should we optimize memory for by-value unary operations? If the type is <code>f64</code>, whose absolute value is also <code>f64</code>, then the following operation is feasible:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">abs</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>This does not allocate new memory to store variable <code>a</code>. But if the type is <code>Complex&lt;f64&gt;</code>, after taking the absolute value it is no longer the original type but <code>f64</code>, meaning with normal code style, the original memory cannot be reused. Therefore, if we want to reuse memory as much as possible, even if <code>f64</code> and <code>Complex&lt;f64&gt;</code> can be unified with the same trait interface, they must take different code paths.<br>
<!-- -->I do not know whether such problems can be implemented in the future with <a href="https://github.com/rust-lang/rust/issues/68318" target="_blank" rel="noopener noreferrer" class="">negative bounds</a> (so that there can be trait restriction strategies based on the inclusion-exclusion principle, instead of the current overly strict orphan rule).</p>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="66-my-misgivings-about-iterators">6.6. My Misgivings about Iterators<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#66-my-misgivings-about-iterators" class="hash-link" aria-label="Direct link to 6.6. My Misgivings about Iterators" title="Direct link to 6.6. My Misgivings about Iterators" translate="no">​</a></h3>
<p>I have doubts about whether iterators are more efficient than for loops.</p>
<p>For many problems, writing with for loops is quite intuitive, and the efficiency loss is not large, if there really is any efficiency loss. Moreover, if iterators were really faster, I believe rustc would recognize the for loop and package its loop part into an FnMut closure, compiling it in the iterator way.</p>
<p>In my view, iterators do have meaning in the following uses:</p>
<ul>
<li class="">Iteration of non-1-D vectors. A tensor structure is not a one-dimensional vector, and there are many different possible iterations; and if written with for loops, it becomes multiple loops (with the number of layers not known at compile time). In this case, iterators are a rigid requirement.</li>
<li class="">Parallelism. When a programming language cannot support parallelism at the syntactic sugar level (like Julia etc.), or cannot support it through macros or precompilation directives (like OpenMP etc.), then functions must be used. Functions must act on objects, so the loop itself must be packaged as an object; this object is the iterator. Rayon iteration, I believe, also came about this way by our scholarly predecessors.</li>
</ul>
<p>There are times when iterators may be more convenient to use, such as the <code>collect::&lt;Vec&lt;T&gt;&gt;()</code> scenario; otherwise we have to create an empty <code>mut Vec&lt;T&gt;</code> outside the loop and add a <code>push(item)</code> statement in the loop body, which is rather troublesome. But this is limited to cases where the loop logic is very simple; if the loop logic is somewhat more complex, for loops are more intuitive instead; and besides, everyone learned C/C++/Python first, and is more used to for loops.</p>
<p>Therefore, when iterators are not a rigid requirement, I do oppose or support using iterators out of code habits (rather than more rational reasons); especially without micro benchmarks testing and proving whether iterators are more efficient than for loops.</p>
<p>At the same time, it should be pointed out that for the problems encountered in electronic structure, iterators can generally be designed to be efficiently parallel; but this costs development time and the cost of mutual adaptation among programmers, and program efficiency may not really lack that little bit, since the main time consumption comes from BLAS; apart from that, the key to improving program efficiency is still the design of the algorithm itself. Therefore, to be honest, I hold a reserved attitude toward designing special iterators; I tend to use for loops; on this point, if I start to deeply understand the bottlenecks of self-consistent field algorithms in the future, I will revisit this problem.</p>
<p>Two iterator-related problems are discussed here.</p>
<ul>
<li class="">
<p><strong>Parallel iterator design.</strong> This is the content of the Rayon library, not my experience. First, my experience is that Rayon's parallelism is in some sense more powerful than C OpenMP; it at least supports double iteration loops, has flexible function interfaces similar to MPI, and in terms of performance, at least in simple problems, I do not see an obvious difference from OpenMP. For OpenMP's simple for loops, Rayon can directly convert to the equivalent</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">n_i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">into_par_iter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">for_each</span><span class="token punctuation" style="color:#393A34">(</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token closure-params">i</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>Although there is some syntactic noise, it is indeed a one-line solution. Unlike OpenMP, the parallel loop body must be <code>Fn</code> rather than <code>FnMut</code>, and cannot pass mut or types that do not implement the <code>Send</code> trait; it may require unsafe or other support to implement the complete OpenMP-like shared parallel mode.</p>
<p>We sometimes need to iterate some structures in parallel, and such structures cannot be solved with simple for loops (such as iterating over all tensor elements). In this case, although implementing <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html" target="_blank" rel="noopener noreferrer" class=""><code>Iterator</code></a> can also be parallel, the <a href="https://docs.rs/rayon/latest/rayon/iter/trait.ParallelBridge.html" target="_blank" rel="noopener noreferrer" class="">bridge</a> mechanism is needed; bridge is very inefficient. To make iterators more efficient, Rayon requires us to provide the following trait implementations:</p>
<ul>
<li class=""><a href="https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html" target="_blank" rel="noopener noreferrer" class=""><code>DoubleEndedIterator</code></a>, i.e., the double-ended iterator;</li>
<li class=""><a href="https://doc.rust-lang.org/std/iter/trait.ExactSizeIterator.html" target="_blank" rel="noopener noreferrer" class=""><code>ExactSizeIterator</code></a>, i.e., the iterator length needs to be known in advance;</li>
<li class=""><a href="https://docs.rs/rayon/latest/rayon/iter/plumbing/trait.Producer.html" target="_blank" rel="noopener noreferrer" class=""><code>Producer</code></a>, which needs to implement the <code>split_at</code> function. An iterator can be seen as a mapping, i.e., a one-to-one correspondence between the iteration list and the continuous integer array. Rayon parallelism needs the mapping from the integer array to the iteration list (but not its inverse); i.e., from the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">x</span></span></span></span>-th iterated element, its iterated content can be deduced. Taking a two-dimensional matrix of size <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>i</mi><mo separator="true">,</mo><mi>j</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(i, j)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mopen">(</span><span class="mord mathnormal">i</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0572em">j</span><span class="mclose">)</span></span></span></span> as an example, the element corresponding to the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">x</span></span></span></span>-th index in row-major is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mo stretchy="false">⌊</mo><mi>x</mi><mi mathvariant="normal">/</mi><mi>j</mi><mo stretchy="false">⌋</mo><mo separator="true">,</mo><mi>x</mi><mtext> </mtext><mo lspace="0.22em" rspace="0.22em"><mrow><mi mathvariant="normal">m</mi><mi mathvariant="normal">o</mi><mi mathvariant="normal">d</mi></mrow></mo><mtext> </mtext><mi>j</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(\lfloor x / j \rfloor, x \bmod j)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mopen">(⌊</span><span class="mord mathnormal">x</span><span class="mord">/</span><span class="mord mathnormal" style="margin-right:0.0572em">j</span><span class="mclose">⌋</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.0556em"></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin"><span class="mord"><span class="mord mathrm">mod</span></span></span><span class="mspace" style="margin-right:0.0556em"></span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0572em">j</span><span class="mclose">)</span></span></span></span>.</li>
<li class=""><a href="https://docs.rs/rayon/latest/rayon/iter/trait.ParallelIterator.html" target="_blank" rel="noopener noreferrer" class=""><code>ParallelIterator</code></a> and <a href="https://docs.rs/rayon/latest/rayon/iter/trait.IndexedParallelIterator.html" target="_blank" rel="noopener noreferrer" class=""><code>IndexedParallelIterator</code></a>; these are the high-level traits in Rayon.</li>
</ul>
</li>
<li class="">
<p><strong>Use array <code>[usize; N]</code> as much as possible and avoid slice <code>[usize]</code>.</strong> This is a problem encountered in high-dimensional tensor indexing, not a problem common to all computational chemistry or programs. We will encounter this problem in <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>C</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub><mo>=</mo><msub><mi>A</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub><mo>+</mo><msub><mi>B</mi><mrow><mi>j</mi><mi>i</mi></mrow></msub></mrow><annotation encoding="application/x-tex">C_{ij} = A_{ij} + B_{ji}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal">A</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">i</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span>, i.e., the matrix transpose summation problem.</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-rstsr-features">7. RSTSR Features<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#7-rstsr-features" class="hash-link" aria-label="Direct link to 7. RSTSR Features" title="Direct link to 7. RSTSR Features" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="71-what-are-rstsrs-design-goals">7.1. What Are RSTSR's Design Goals?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#71-what-are-rstsrs-design-goals" class="hash-link" aria-label="Direct link to 7.1. What Are RSTSR's Design Goals?" title="Direct link to 7.1. What Are RSTSR's Design Goals?" translate="no">​</a></h3>
<ul>
<li class="">Function style: as consistent with NumPy as possible, as simple and easy to use as possible and conforming to NumPy habits.</li>
<li class="">Functionality: most of the NumPy main program, SciPy's scipy.linalg and scipy.linalg.blas.<!-- -->
<ul>
<li class="">Most math libraries in other compiled languages are also benchmarked against NumPy, represented by xTensor (C++), ndarray (Rust), GoNum (Go) and NumSharp (C#). NumPy is of course not the best math library, but there is nothing shameful in using it as a reference.</li>
</ul>
</li>
<li class="">CPU performance: matrix multiplication connects to BLAS; most of the other operators are faster than serial NumPy under 8-core parallelism. It allows flexible integration of Rayon parallel code.</li>
<li class="">Backends: hope to support GPU programming in the future (including CUDA, HIP).</li>
<li class="">Types: support data storage of all types through trait generics; support computation of some types through <code>std::ops</code> and the crate <code>num</code>.</li>
</ul>
<p>Electronic structure programs not only pursue the above goals, but also need to implement electronic structure algorithms themselves, and even use algorithms not available in standard math libraries. My knowledge breadth is not enough, but I previously heard that a student of Prof. Ren Xingguo (<a href="https://amphds.yingzhouli.com/download_file/2024Spring/20240509.pdf" target="_blank" rel="noopener noreferrer" class="">poster</a>) used oneMKL PARDISO when implementing basis-set-limit RPA. Obviously the features chemistry needs are broader than those of general math libraries. Therefore, even just for writing electronic structure programs, these simple mathematical program tools are worth developing.</p>
<p>For RSTSR's goals and the survey briefing on other Rust or non-Rust math libraries, the RSTSR 1st report has more detailed descriptions.</p>
<p>At the same time, it should be noted that although RSTSR is designed for electronic structure program purposes, it is still a math library, not an electronic structure library. Electronic structure programs can separate part of their mathematical problems into a self-contained system, and the problems that can be solved are not limited to electronic structure; therefore we should not force the claim that RSTSR is a math library with electronic structure computing features. Our vision can and should be longer-term.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="72-what-features-does-rstsr-currently-have-what-is-still-lacking-for-electronic-structure">7.2. What Features Does RSTSR Currently Have? What Is Still Lacking for Electronic Structure?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#72-what-features-does-rstsr-currently-have-what-is-still-lacking-for-electronic-structure" class="hash-link" aria-label="Direct link to 7.2. What Features Does RSTSR Currently Have? What Is Still Lacking for Electronic Structure?" title="Direct link to 7.2. What Features Does RSTSR Currently Have? What Is Still Lacking for Electronic Structure?" translate="no">​</a></h3>
<p>With a total of about 3 months of development time (7/28–8/5, 8/11–10/6, 12/22–1/21, during which other work such as the RHF first-order gradient implementation draft under REST was completed), RSTSR has currently completed most of the basic features required of math libraries by the Python array API standard. Please refer to the electronic structure needs for math libraries in <a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#how-elec-needs-num" class="">What math library features do electronic structure programs need?</a>.</p>
<p>I myself also, based on the following three-step workflow: 1) drafting with NumPy np.einsum, 2) removing np.einsum in NumPy to prepare for migration to Rust, 3) concretely implementing the algorithm based on the math library RSTSR, starting from the non-RI closed-shell CCSD <a href="https://pycrawfordprogproj.readthedocs.io/en/latest/Project_05/Project_05.html" target="_blank" rel="noopener noreferrer" class="">tutorial document</a>, and essentially without drawing on derivations in existing literature, implemented closed-shell RI-CCSD in Rust (<a href="https://github.com/ajz34/showcase_rust_riccsd" target="_blank" rel="noopener noreferrer" class="">showcase_rust_riccsd</a>), taking less than 4 days in total (2025/1/17–2025/1/20), with program performance at least comparable to the Psi4 fnocc module, though the memory overhead was not yet more carefully optimized. I hope this project can show that the NumPy + Rust workflow strategy, aided by a relatively complete Rust math library, is entirely capable of achieving efficient and rapid implementation of electronic structure methods.</p>
<p>RSTSR still has many deficiencies to solve.</p>
<ul>
<li class="">It does not satisfy all function requirements of the Python array API standard, including concat, stack, argmax, etc.</li>
<li class="">The BLAS and Lapack wrappers and the linear algebra part are not implemented; this means RSTSR currently has no definite solution for how to solve matrix eigenvalue or vector solving problems. Therefore, the current RSTSR cannot yet do SCF, CP-HF, Cholesky decomposition, or the matrix logarithm or determinant computations needed by RPA.</li>
<li class="">There are no correctness and efficiency tests. Before starting the RI-CCSD implementation, I kept adding features to RSTSR and had not yet done any correctness verification. So it is entirely possible that RSTSR has numerical errors. Of course, during the RI-CCSD implementation, there was only one rather benign bug fix (removing an overly strict trait bound), so I still hold great expectations for program correctness.</li>
<li class="">Some advanced indexing features of NumPy are not implemented, especially indexing tensors by integer lists.</li>
<li class="">Heterogeneous backends are not implemented. Although multiple backends are currently implemented, they are generally only used to switch between different BLAS engines, verifying the possibility of multi-backend implementation. A true multi-backend should consider CUDA and HIP, and for MacOS, Accelerate and Metal.</li>
<li class="">More implementation and testing on more electronic structure problems is still needed.</li>
<li class="">Adaptability under MPI parallelism has not been verified.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="rstsr-pro">7.3. Why Not Be Satisfied with Existing Tools? Which RSTSR Features Are Advantageous?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#rstsr-pro" class="hash-link" aria-label="Direct link to 7.3. Why Not Be Satisfied with Existing Tools? Which RSTSR Features Are Advantageous?" title="Direct link to 7.3. Why Not Be Satisfied with Existing Tools? Which RSTSR Features Are Advantageous?" translate="no">​</a></h3>
<ul>
<li class="">
<p><strong>Supports complete n-dimensional arrays and their broadcasting.</strong> This is relative to ndarray; it only supports partial broadcasting and manipulation functions, and should be considered half-finished. Many other Rust math libraries do not support n-dimensional arrays, notably nalgebra, faer, etc. There are also libraries that do not support dynamic-dimension tensors (possibly because of computational graph construction), notably dfdx, burn, etc.</p>
</li>
<li class="">
<p><strong>Supports floating point types and complex floating point types.</strong> Rust's current machine learning libraries generally do not support complex floating point, notably candle, burn, etc. To be honest, candle is the framework closest to a tensor library usable for computational chemistry, but its design pattern is the same as PyTorch's, not very extensible (although it was an excellent design 10 years ago), with types and backends hard-coded in the core program. This conflicts considerably with my development philosophy. In extensibility, we are closer to burn; but burn does not satisfy our needs in data types and variable dimensions.</p>
</li>
<li class="">
<p><strong>We plan to support multiple backends.</strong> This is relative to NumPy and ndarray. nalgebra abandoned its CUDA backend a few years ago. PyTorch is now invincible; if our own functions cannot beat PyTorch at anything, perhaps we can make PyTorch our backend in the future. But no matter which engine is the backend, basic arbitrary-dimension tensors, reshape, transpose and other features still need to be implemented in Rust; C++ cannot help with this.</p>
</li>
<li class="">
<p><strong>CPU parallelism of internal operators.</strong> This feature means that apart from BLAS computations that can be accelerated with ready-made libraries, the performance of the rest is also considerable; but we have not spent much energy on this, and obviously the limit efficiency is not yet reachable, but at least we will not be dragged down too much. Almost all math libraries represented by NumPy and ndarray only parallelize BLAS, and do not parallelize elsewhere. But a small number of math libraries with this feature have better performance than ours, represented by PyTorch.</p>
</li>
<li class="">
<p><strong>Seamless external Rayon parallelism.</strong> Most functions of this library can run inside Rayon threads.</p>
</li>
<li class="">
<p><strong>BLAS supports serial and parallel calls.</strong> This is learned from rest_tensors. Inside Rayon parallelism, the number of BLAS cores will be limited to one; without a parallel environment, it runs at full CPU; the number of concurrent cores can also be controlled in the device. In my understanding, ndarray and nalgebra do not support this feature; this type of feature requires specialization for each BLAS distribution to implement, rather than relying on the crate <code>blas-sys</code> as a one-size-fits-all solution; otherwise problems easily occur when calling BLAS in parallel with Rayon.</p>
</li>
<li class="">
<p><strong>A concise interface form close to NumPy.</strong> Taking the sum function as an example, our sum function requires passing the list of dimensions to be summed; for example, when computing the dipole moment, we need to compute the elementwise multiplication and summation of the one-electron integrals and the density matrix:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// tsr_int1e_r: (t, mu, nu); rdm1: (mu, nu)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> dipole </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tsr_int1e_r </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> rdm1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">sum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>But in ndarray, it needs to be written as</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> dip </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tsr_int1e_r </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> rdm1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">sum_axis</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Axis</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">sum_axis</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Axis</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>Not only is the code more complex, the computation cost also increases. Another example is the <code>asarray</code> function, which we overload using the trait overload pattern; but ndarray requires using many functions like <code>from_vec</code>, <code>from_shape</code>, <code>from_shape_vec</code>, <code>from_shape_ptr</code> to do one thing, which is unfriendly to users.</p>
</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="731-an-operator-where-rstsr-has-some-advantage-elementwise-multiplication-with-transposed-matrix-mathbfc--mathbfa-odot-mathbfbt">7.3.1. An Operator Where RSTSR Has Some Advantage: Elementwise Multiplication with Transposed Matrix <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">C</mi><mo>=</mo><mi mathvariant="bold">A</mi><mo>⊙</mo><msup><mi mathvariant="bold">B</mi><mi>T</mi></msup></mrow><annotation encoding="application/x-tex">\mathbf{C} = \mathbf{A} \odot \mathbf{B}^{T}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">C</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.7694em;vertical-align:-0.0833em"></span><span class="mord mathbf">A</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">⊙</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.8413em"></span><span class="mord"><span class="mord mathbf">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8413em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">T</span></span></span></span></span></span></span></span></span></span></span></span><a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#731-an-operator-where-rstsr-has-some-advantage-elementwise-multiplication-with-transposed-matrix-mathbfc--mathbfa-odot-mathbfbt" class="hash-link" aria-label="Direct link to 731-an-operator-where-rstsr-has-some-advantage-elementwise-multiplication-with-transposed-matrix-mathbfc--mathbfa-odot-mathbfbt" title="Direct link to 731-an-operator-where-rstsr-has-some-advantage-elementwise-multiplication-with-transposed-matrix-mathbfc--mathbfa-odot-mathbfbt" translate="no">​</a></h4>
<p>Previously, on the operator <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>C</mi><mi>g</mi></msub><mo>=</mo><msub><mo>∑</mo><mi>i</mi></msub><msub><mi>A</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub><msub><mi>B</mi><mrow><mi>i</mi><mi>g</mi></mrow></msub></mrow><annotation encoding="application/x-tex">C_g = \sum_i A_{ig} B_{ig}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">C</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.0497em;vertical-align:-0.2997em"></span><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:0em">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.162em"><span style="top:-2.4003em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2997em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal">A</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0502em">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0502em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span> problem, we were thrashed by NumPy's np.einsum; now it is time to win one back.</p>
<p>In MP2 computation, the following computational problem appears:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mtable rowspacing="0.25em" columnalign="right left" columnspacing="0em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msubsup><mi>e</mi><mrow><mi>i</mi><mi>j</mi></mrow><mtext>bi1</mtext></msubsup></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mrow><mi>a</mi><mi>b</mi></mrow></munder><msubsup><mi>t</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>a</mi><mi>b</mi></mrow></msubsup><msubsup><mi>g</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>a</mi><mi>b</mi></mrow></msubsup></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msubsup><mi>e</mi><mrow><mi>i</mi><mi>j</mi></mrow><mtext>bi2</mtext></msubsup></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mrow><mi>a</mi><mi>b</mi></mrow></munder><msubsup><mi>t</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>a</mi><mi>b</mi></mrow></msubsup><msubsup><mi>g</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>b</mi><mi>a</mi></mrow></msubsup></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msub><mi>e</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mn>2</mn><msubsup><mi>e</mi><mrow><mi>i</mi><mi>j</mi></mrow><mtext>bi1</mtext></msubsup><mo>−</mo><msubsup><mi>e</mi><mrow><mi>i</mi><mi>j</mi></mrow><mtext>bi2</mtext></msubsup></mrow></mstyle></mtd></mtr></mtable><annotation encoding="application/x-tex">\begin{aligned}
e_{ij}^{\text{bi1}} &amp;= \sum_{ab} t_{ij}^{ab} g_{ij}^{ab} \\
e_{ij}^{\text{bi2}} &amp;= \sum_{ab} t_{ij}^{ab} g_{ij}^{ba} \\
e_{ij} &amp;= 2 e_{ij}^{\text{bi1}} - e_{ij}^{\text{bi2}}
\end{aligned}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:6.5865em;vertical-align:-3.0432em"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:3.5432em"><span style="top:-5.5432em"><span class="pstrut" style="height:3.05em"></span><span class="mord"><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">bi1</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span></span></span><span style="top:-2.8911em"><span class="pstrut" style="height:3.05em"></span><span class="mord"><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">bi2</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span></span></span><span style="top:-0.3899em"><span class="pstrut" style="height:3.05em"></span><span class="mord"><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:3.0432em"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:3.5432em"><span style="top:-5.5432em"><span class="pstrut" style="height:3.05em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8479em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em">g</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span></span></span><span style="top:-2.8911em"><span class="pstrut" style="height:3.05em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8479em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em">g</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ba</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span></span></span><span style="top:-0.3899em"><span class="pstrut" style="height:3.05em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mord">2</span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">bi1</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">bi2</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:3.0432em"><span></span></span></span></span></span></span></span></span></span></span></span>
<p>This operator is actually a fused operator of elementwise multiplication followed by summation, and it is best to implement it by the original formula; but for implementation convenience, for each pair of occupied orbitals <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>i</mi><mo separator="true">,</mo><mi>j</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(i, j)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mopen">(</span><span class="mord mathnormal">i</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0572em">j</span><span class="mclose">)</span></span></span></span>, two matrix elementwise multiplications are done: one without transpose, one with transpose:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mtable rowspacing="0.25em" columnalign="right left" columnspacing="0em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msubsup><mi>E</mi><mrow><mi>a</mi><mi>b</mi></mrow><mtext>bi1</mtext></msubsup></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><msub><mi>T</mi><mrow><mi>a</mi><mi>b</mi></mrow></msub><msub><mi>g</mi><mrow><mi>a</mi><mi>b</mi></mrow></msub></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msubsup><mi>E</mi><mrow><mi>a</mi><mi>b</mi></mrow><mtext>bi2</mtext></msubsup></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><msub><mi>T</mi><mrow><mi>a</mi><mi>b</mi></mrow></msub><msub><mi>g</mi><mrow><mi>b</mi><mi>a</mi></mrow></msub></mrow></mstyle></mtd></mtr></mtable><annotation encoding="application/x-tex">\begin{aligned}
E_{ab}^{\text{bi1}} &amp;= T_{ab} g_{ab} \\
E_{ab}^{\text{bi2}} &amp;= T_{ab} g_{ba}
\end{aligned}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.8182em;vertical-align:-1.1591em"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6591em"><span style="top:-3.76em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.0576em">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:-0.0576em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">bi1</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span></span></span><span style="top:-2.2009em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.0576em">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:-0.0576em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">bi2</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.1591em"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6591em"><span style="top:-3.76em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em">g</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span><span style="top:-2.2009em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em">g</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ba</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.1591em"><span></span></span></span></span></span></span></span></span></span></span></span>
<p>This is the origin of the operators <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">C</mi><mo>=</mo><mi mathvariant="bold">A</mi><mo>⊙</mo><mi mathvariant="bold">B</mi></mrow><annotation encoding="application/x-tex">\mathbf{C} = \mathbf{A} \odot \mathbf{B}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">C</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.7694em;vertical-align:-0.0833em"></span><span class="mord mathbf">A</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">⊙</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">B</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">C</mi><mo>=</mo><mi mathvariant="bold">A</mi><mo>⊙</mo><msup><mi mathvariant="bold">B</mi><mi>T</mi></msup></mrow><annotation encoding="application/x-tex">\mathbf{C} = \mathbf{A} \odot \mathbf{B}^{T}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">C</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.7694em;vertical-align:-0.0833em"></span><span class="mord mathbf">A</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">⊙</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.8413em"></span><span class="mord"><span class="mord mathbf">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8413em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">T</span></span></span></span></span></span></span></span></span></span></span></span> we are examining.</p>
<p>Logically this operator should not take much time, since it is quadratic in time (multiplied by the pairs of occupied orbitals, the FLOPs is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><msubsup><mi>n</mi><mtext>occ</mtext><mn>2</mn></msubsup><msubsup><mi>n</mi><mtext>vir</mtext><mn>2</mn></msubsup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(n_{\text{occ}}^2 n_{\text{vir}}^2)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0786em;vertical-align:-0.2645em"></span><span class="mord mathnormal" style="margin-right:0.0278em">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">occ</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.4355em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">vir</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2645em"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span>, much smaller than the 5th-power complexity <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi>n</mi><mtext>occ</mtext><mn>2</mn></msubsup><msubsup><mi>n</mi><mtext>vir</mtext><mn>2</mn></msubsup><msub><mi>n</mi><mtext>aux</mtext></msub></mrow><annotation encoding="application/x-tex">n_{\text{occ}}^2 n_{\text{vir}}^2 n_{\text{aux}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0786em;vertical-align:-0.2645em"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">occ</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.4355em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">vir</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2645em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">aux</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> of the whole RI-MP2).</p>
<p>But if implemented with NumPy, the efficiency becomes very bad. First, RI-MP2 is naturally easy to parallelize over pairs of occupied orbitals <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>i</mi><mo separator="true">,</mo><mi>j</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(i, j)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mopen">(</span><span class="mord mathnormal">i</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0572em">j</span><span class="mclose">)</span></span></span></span>; but constrained by Python syntax, in pure Python we should not think about parallelizing for loops. NumPy's matrix multiplication uses BLAS, so even without parallelizing over pairs of occupied orbitals <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>i</mi><mo separator="true">,</mo><mi>j</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(i, j)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mopen">(</span><span class="mord mathnormal">i</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0572em">j</span><span class="mclose">)</span></span></span></span>, obtaining the MO-basis 4c-2e ERIs from Cholesky-decomposed ERIs is still fast; that is, NumPy's efficiency in the computational bottleneck part is guaranteed.</p>
<p>But for computing the elementwise matrix multiplication of the non-bottleneck part, NumPy has efficiency problems. Now suppose a system with 512 electrons, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>n</mi><mtext>occ</mtext></msub><mo>=</mo><mn>256</mn></mrow><annotation encoding="application/x-tex">n_{\text{occ}} = 256</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">occ</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">256</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>n</mi><mtext>vir</mtext></msub><mo>=</mo><mn>1024</mn></mrow><annotation encoding="application/x-tex">n_{\text{vir}} = 1024</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3175em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">vir</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">1024</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>n</mi><mtext>aux</mtext></msub><mo>=</mo><mn>3072</mn></mrow><annotation encoding="application/x-tex">n_{\text{aux}} = 3072</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">aux</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">3072</span></span></span></span>; on my 16-core CPU laptop, assuming BLAS can reach 55% performance (600 GFLOP/sec), then the time for the computational bottleneck part of RI-MP2 is 328 sec.</p>
<p>So it seems the energy summation computation should not be the bottleneck, right? But running the code, you will find that for NumPy, the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1024</mn><mo>×</mo><mn>1024</mn></mrow><annotation encoding="application/x-tex">1024 \times 1024</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">1024</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">1024</span></span></span></span> matrix computations</p>
<ul>
<li class="">normal elementwise multiplication <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">C</mi><mo>=</mo><mi mathvariant="bold">A</mi><mo>⊙</mo><mi mathvariant="bold">B</mi></mrow><annotation encoding="application/x-tex">\mathbf{C} = \mathbf{A} \odot \mathbf{B}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">C</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.7694em;vertical-align:-0.0833em"></span><span class="mord mathbf">A</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">⊙</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">B</span></span></span></span> is 250 µsec,</li>
<li class="">transposed elementwise multiplication <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">C</mi><mo>=</mo><mi mathvariant="bold">A</mi><mo>⊙</mo><msup><mi mathvariant="bold">B</mi><mi>T</mi></msup></mrow><annotation encoding="application/x-tex">\mathbf{C} = \mathbf{A} \odot \mathbf{B}^{T}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">C</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.7694em;vertical-align:-0.0833em"></span><span class="mord mathbf">A</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">⊙</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.8413em"></span><span class="mord"><span class="mord mathbf">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8413em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">T</span></span></span></span></span></span></span></span></span></span></span></span> is 5.3 msec,</li>
<li class="">matrix summation <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>e</mi><mo>=</mo><mtext>sum</mtext><mo stretchy="false">(</mo><mi mathvariant="bold">C</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">e = \text{sum}(\mathbf{C})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord text"><span class="mord">sum</span></span><span class="mopen">(</span><span class="mord mathbf">C</span><span class="mclose">)</span></span></span></span> is 130 µsec, needing to be computed twice,</li>
</ul>
<p>combined with the loop over <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mi>n</mi><mtext>occ</mtext><mn>2</mn></msubsup><mi mathvariant="normal">/</mi><mn>2</mn><mo>=</mo><mn>32768</mn></mrow><annotation encoding="application/x-tex">n_{\text{occ}}^2 / 2 = 32768</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0641em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">occ</span></span></span></span></span><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em"><span></span></span></span></span></span></span><span class="mord">/2</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">32768</span></span></span></span> pairs of occupied orbitals, the above computation is estimated to take 190 sec. This already reaches 60% of the bottleneck computation time, not a negligible amount.</p>
<p>In NumPy, the part with efficiency problems is the transposed elementwise multiplication <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">C</mi><mo>=</mo><mi mathvariant="bold">A</mi><mo>⊙</mo><msup><mi mathvariant="bold">B</mi><mi>T</mi></msup></mrow><annotation encoding="application/x-tex">\mathbf{C} = \mathbf{A} \odot \mathbf{B}^{T}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">C</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.7694em;vertical-align:-0.0833em"></span><span class="mord mathbf">A</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">⊙</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.8413em"></span><span class="mord"><span class="mord mathbf">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8413em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">T</span></span></span></span></span></span></span></span></span></span></span></span>, and the summation <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>e</mi><mo>=</mo><mtext>sum</mtext><mo stretchy="false">(</mo><mi mathvariant="bold">C</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">e = \text{sum}(\mathbf{C})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord text"><span class="mord">sum</span></span><span class="mopen">(</span><span class="mord mathbf">C</span><span class="mclose">)</span></span></span></span> is also inefficient; but the efficiency that can be gained from summation is limited. In Rust, we can naturally parallelize this problem over pairs of occupied orbitals <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>i</mi><mo separator="true">,</mo><mi>j</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(i, j)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mopen">(</span><span class="mord mathnormal">i</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0572em">j</span><span class="mclose">)</span></span></span></span>, thus alleviating the problem. This is one solution.</p>
<p>But even without parallelizing over pairs of occupied orbitals <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>i</mi><mo separator="true">,</mo><mi>j</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(i, j)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mopen">(</span><span class="mord mathnormal">i</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.0572em">j</span><span class="mclose">)</span></span></span></span>, with only ordinary for loops, RSTSR can achieve very good performance on the RI-MP2 energy summation.</p>
<p>In RSTSR, if the input <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">A</mi></mrow><annotation encoding="application/x-tex">\mathbf{A}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">A</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">B</mi></mrow><annotation encoding="application/x-tex">\mathbf{B}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">B</span></span></span></span> are of fixed dimension <code>Ix2</code>, executed in parallel,</p>
<ul>
<li class="">the transposed elementwise multiplication <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">C</mi><mo>=</mo><mi mathvariant="bold">A</mi><mo>⊙</mo><msup><mi mathvariant="bold">B</mi><mi>T</mi></msup></mrow><annotation encoding="application/x-tex">\mathbf{C} = \mathbf{A} \odot \mathbf{B}^{T}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">C</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.7694em;vertical-align:-0.0833em"></span><span class="mord mathbf">A</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">⊙</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.8413em"></span><span class="mord"><span class="mord mathbf">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8413em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">T</span></span></span></span></span></span></span></span></span></span></span></span> can be improved to 310 µsec (ndarray is 3.7 msec),</li>
<li class="">the matrix summation <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>e</mi><mo>=</mo><mtext>sum</mtext><mo stretchy="false">(</mo><mi mathvariant="bold">C</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">e = \text{sum}(\mathbf{C})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord text"><span class="mord">sum</span></span><span class="mopen">(</span><span class="mord mathbf">C</span><span class="mclose">)</span></span></span></span> is 38 µsec (ndarray is 84 µsec).</li>
</ul>
<p>For the transposed elementwise multiplication problem, RSTSR's performance improvement is greater than the 16-times ideal parallel efficiency. As a bandwidth-bottleneck problem, normal parallel performance improvement depends on the specific problem, ranging 0.8–8 times (for simple computation problems with good contiguity, parallelism is sometimes a negative optimization). This may be related to RSTSR's iterator design.</p>
<p>For RSTSR, we estimate the above RI-MP2 energy summation problem takes 21 sec, about 9 times faster than NumPy, much smaller than the 328 sec of the computational bottleneck of the MO-basis 4c-2e ERIs. This is how the problem is solved: for the parts that are not performance-critical, even if the most convenient implementation is used rather than the most efficient algorithm, the program efficiency must still be satisfactory. But it should be pointed out that PyTorch may have implementation efficiency close to or better than RSTSR.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="74-what-design-flaws-does-rstsr-have-that-may-need-early-discussion-or-complete-refactoring">7.4. What Design Flaws Does RSTSR Have That May Need Early Discussion or Complete Refactoring?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#74-what-design-flaws-does-rstsr-have-that-may-need-early-discussion-or-complete-refactoring" class="hash-link" aria-label="Direct link to 7.4. What Design Flaws Does RSTSR Have That May Need Early Discussion or Complete Refactoring?" title="Direct link to 7.4. What Design Flaws Does RSTSR Have That May Need Early Discussion or Complete Refactoring?" translate="no">​</a></h3>
<p>Under the current RSTSR framework, I have not come up with good solutions for some problems. I also hope that the following problems I have thought of, and the problems I may not have thought of, will be discussed as early as possible:</p>
<ul>
<li class=""><strong>Complex matrix conjugation.</strong> Currently RSTSR's implementation is consistent with NumPy, i.e., <code>a.conj()</code> produces a new matrix with memory reallocated. Therefore, computations like <code>a.conj().T @ &amp;b</code> are inherently inefficient and memory-consuming. This can of course be solved by introducing safe BLAS interfaces, letting users choose whether to use more efficient BLAS functions; but this creates some syntactic noise.</li>
<li class=""><strong>Matrix types.</strong> We do not always deal with arbitrary dense matrices; we may also deal with diagonal matrices, tridiagonal matrices, symmetric matrices, antisymmetric matrices, Hermitian matrices, anti-Hermitian matrices, lower triangular matrices, strictly lower triangular matrices, upper triangular matrices, strictly upper triangular matrices, banded sparse matrices, etc. As a tensor library, we may not need very complete support for two-dimensional matrices; NumPy is also somewhat criticized in this respect, and later GoNum, nalgebra, Faer implemented some of these matrix types differently from ordinary matrices. But if we decide to support these types of matrices, it means we need to re-discuss the storage and computation logic of tensors.<!-- -->
<ul>
<li class="">At the same time, it should be pointed out that GoNum, nalgebra, Faer are all clearly libraries that only handle two-dimensional matrices or one-dimensional vectors. I have not found an n-dimensional tensor library that supports different matrix types.</li>
<li class="">It is also added here that PySCF generally decompresses lower triangular packed matrices (row-major) before computation. This approach usually does not introduce too much extra efficiency loss.</li>
</ul>
</li>
<li class=""><strong>Automatic differentiation.</strong> To be honest, this is limited by my personal ability. I have not yet grasped the principles of computational graphs. Electronic structure certainly does not need automatic differentiation, but this is now the basic requirement of the AI direction for math libraries. We are of course not unable to make an inference-only library; implementing a few operators without derivatives should not be difficult, but that would be boring. If we want to lean toward the AI direction, I think experienced people need to get involved; but in the end, I myself work on electronic structure, and indeed have no motivation to do automatic differentiation. I do not know how big the demand for AI + first-principles is, nor whether candle and burn can now serve as automatic-differentiation tensor libraries in Rust and be applied to chemistry problems.</li>
<li class=""><strong>Compilation time is too long.</strong> I do not know the cause or solution. It may be that there are too many impls in one type.</li>
</ul>
<p>The following are problems I have the ability to solve, but they also need early discussion:</p>
<ul>
<li class="">
<p><strong>Col-major.</strong> The current RSTSR defaults to row-major. In RSTSR, the concrete algorithms are all implemented column-major; column-major indeed has better efficiency. But we completely separated the concrete algorithms from the high-level interface; currently the high-level interface is only designed and implemented in the row-major environment. Whether we should explicitly support col-major and implement its corresponding broadcasting rules for col-major, I am confident I can implement, but if there is a need, it needs early discussion.</p>
<ul>
<li class="">We need to explain that when RSTSR internally implements tensor addition and subtraction, it will try to transpose tensors to col-major before computation. Therefore, whether the high-level interface is col-major or row-major does not affect computational efficiency. Tensor transposition certainly has a performance cost, but this cost is nothing more than the addition, subtraction and multiplication of five or six integers (layout manipulation), which is insignificant in electronic structure problems.</li>
<li class="">The broadcasting of col-major should be redesigned. NumPy's broadcasting rules are clearly more friendly to row-major. I do not know whether other tensor libraries have made similar attempts.</li>
</ul>
</li>
<li class="">
<p><strong>Data types and cast principles.</strong> For example, <code>np.log(2)</code> gives a floating point number, but the current crate <code>num</code> does not provide a log function for integer types or their corresponding traits. Which functions, which traits, and how to implement them, these problems need further discussion. Electronic structure generally does not use common and special functions; even if needed, although not very elegant, we have ways like <code>.mapv(|x| x.log())</code>. The Map function design is modeled after ndarray.</p>
</li>
<li class="">
<p><strong>Complex trait impls.</strong> The current RSTSR seems to have trait impls that are too tedious on some problems, so much so that the Rust compiler can no longer automatically infer types. I encountered this when writing RI-CCSD, and it is one of the least smooth parts of implementing RI-CCSD in my view. For example,</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2.0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">slice</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>In the RI-CCSD implementation, this may very likely fail to compile because the type cannot be inferred. You must add this line to make it compile:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Tensor</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">f64</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> _</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2.0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">slice</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>In my Rust development, except for the <code>collect::&lt;Vec&lt;T&gt;&gt;()</code> function, I have never encountered a similar problem. I think we need to find a way to avoid errors caused by overly complex impls.</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="8-rstsr-design">8. RSTSR Design<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#8-rstsr-design" class="hash-link" aria-label="Direct link to 8. RSTSR Design" title="Direct link to 8. RSTSR Design" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="81-what-is-rstsrs-data-structure-is-it-suitable-for-any-dense-tensor">8.1. What Is RSTSR's Data Structure? Is It Suitable for Any Dense Tensor?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#81-what-is-rstsrs-data-structure-is-it-suitable-for-any-dense-tensor" class="hash-link" aria-label="Direct link to 8.1. What Is RSTSR's Data Structure? Is It Suitable for Any Dense Tensor?" title="Direct link to 8.1. What Is RSTSR's Data Structure? Is It Suitable for Any Dense Tensor?" translate="no">​</a></h3>
<p>RSTSR's current data structure is shown in the figure below:</p>
<p><img decoding="async" loading="lazy" alt="RSTSR data structure" src="https://restgroup.github.io/rstsr-book/assets/images/rstsr-basic-structure-2-cd99e6e423b65b46c9677fbbbe284760.png" width="2984" height="1729" class="img_ev3q"></p>
<p>I believe the above figure is already intuitive, so it will not be expanded in detail here.</p>
<p>RSTSR's code has undergone a complete refactoring, and it differs from the initial data structure. Please refer to pages 12–13 of the RSTSR 1st report. Specifically, the current data is under storage; previously it was the other way around.</p>
<p>RSTSR's data structure is <strong>not suitable</strong> for all types of dense tensors, especially small dense tensors. In RSTSR's tensors, besides <code>tensor.data</code> which stores the raw data, shape, stride, offset, device also need to be stored. We can call these the tensor's metadata.</p>
<ul>
<li class="">shape is <code>Vec&lt;usize&gt;</code> or <code>[usize; N]</code>, its length depends on the tensor dimension; generally no more than 512 bits;</li>
<li class="">stride is the same as shape, but the type is <code>isize</code>; generally no more than 512 bits;</li>
<li class="">offset is usize, 8 bits in length;</li>
<li class="">device depends on the concrete backend:<!-- -->
<ul>
<li class=""><code>DeviceCpuSerial</code> is just a marker and does not occupy stack space;</li>
<li class="">backends involving parallelism need to use <code>DeviceCpuRayon</code>; it consists of the CPU thread count, the Arc of the global thread pool, and the Arc of the single-thread pool, totaling 24 bits of stack space; creating the global thread pool and the single-thread pool is estimated to need at least 2048 bits of heap space, but Arc pointers guarantee that all tensors share the same heap space, so this heap space can be counted outside the tensor.</li>
</ul>
</li>
<li class="">Therefore, a <code>TensorBase</code> type needs an extra 1024 bits, i.e., 16 floating point numbers, besides the data.</li>
</ul>
<p>For electronic structure, when the basis set size exceeds 100, the redundant information needed to store a tensor in memory does not exceed 2‰, which should be acceptable. But for game rendering, one dimension is generally fixed to 3, and the other dimension is also often fixed and no more than 6; in this case, fixed dimensions are better, i.e., increasing the size of the compiled binary by dispatch (specializing) matrix types of different fixed dimensions (to represent the tensor's metadata), while only raw data is needed when storing the tensor. Libraries like nalgebra, dfdx support fixed dimensions and are more suitable for the latter work. But general scientific computing handles very large matrices and does not need fixed-dimension support.</p>
<p>I have some misgivings about why machine learning libraries support fixed dimensions. For the earliest MLPs and CNNs, models generally fix the hidden layer or channel dimensions; CNN convolution kernels are generally <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>3</mn><mo>×</mo><mn>3</mn></mrow><annotation encoding="application/x-tex">3 \times 3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">3</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">3</span></span></span></span> or <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>5</mn><mo>×</mo><mn>5</mn></mrow><annotation encoding="application/x-tex">5 \times 5</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">5</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">5</span></span></span></span> in dimension, and also have the feature of small individual dimensions (but at the same time it should be noted that CNN convolution kernel parameters also include input and output channels; if both are 64, the tensor size is at least <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>3</mn><mo>×</mo><mn>3</mn><mo>×</mo><mn>64</mn><mo>×</mo><mn>64</mn><mo>≈</mo><mn>35000</mn></mrow><annotation encoding="application/x-tex">3 \times 3 \times 64 \times 64 \approx 35000</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">3</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">3</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">64</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">64</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">35000</span></span></span></span>, which is definitely not a small tensor). Fixing some dimensions helps compiler optimization, and also helps JIT optimization; but in the limit, these automatic optimizations either cannot beat manual optimization, or can judge dimensions and implement with dispatch in a dynamic-dimension framework.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="82-what-are-the-tensor-layout-operations-do-they-cost-computational-performance">8.2. What Are the Tensor Layout Operations? Do They Cost Computational Performance?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#82-what-are-the-tensor-layout-operations-do-they-cost-computational-performance" class="hash-link" aria-label="Direct link to 8.2. What Are the Tensor Layout Operations? Do They Cost Computational Performance?" title="Direct link to 8.2. What Are the Tensor Layout Operations? Do They Cost Computational Performance?" translate="no">​</a></h3>
<p>Typical Layout operations include</p>
<ul>
<li class="">Basic indexing, i.e., extracting sub-tensors or sub-matrices according to certain rules; but depending on the situation, it may also add several dimensions;</li>
<li class="">Transpose, i.e., the rotation of several index labels of a tensor;</li>
<li class="">Reshape, i.e., changing the shape of a tensor.</li>
</ul>
<p>Among these Layout operations, basic indexing and transpose do not concretely change the tensor's data. For reshape, when the tensor's underlying data has a certain contiguity (which is generally the case), it also does not change the tensor's data; but when the tensor's data is not contiguously stored, it depends on the situation.</p>
<p>When the tensor's data is not changed, <strong>layout operations cost no computational performance</strong>. If there is a cost, it is often only a complex operation within 10 integers; compared to electronic structure problems, this amount of operation is unimportant. We need to emphasize that what we do is electronic structure, because I estimate that in some fields, people do care about this little bit of cost.</p>
<p>In the RSTSR program, apart from designing layout-based iterators, we do not optimize the performance of layout operations at all (including but not limited to broadcast, split_at, translate_to_col_major, etc.). Clone when it is time to clone, and reach for <code>Vec&lt;usize&gt;</code> on the heap when it is time, without any hesitation.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="83-how-are-tensor-iterators-designed">8.3. How Are Tensor Iterators Designed?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#83-how-are-tensor-iterators-designed" class="hash-link" aria-label="Direct link to 8.3. How Are Tensor Iterators Designed?" title="Direct link to 8.3. How Are Tensor Iterators Designed?" translate="no">​</a></h3>
<p>First, the tensor iterators we implement are all based on layout iterators. How a tensor is iterated depends on the tensor's shape, stride, offset, and has nothing to do with the tensor's elements. Therefore, the tensor's iterators and the layout's iterators should be separated.</p>
<p>Layout iterators iterate over the tensor's indices (for example, for a matrix it is the two-dimensional usize array <code>[i, j]</code>), and output the relative address in memory of that index as usize. Based on this, the tensor's iterators (which also iterate over indices, but output values or their references) are easy to implement.</p>
<p>In the file <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/layout/iterator.rs" target="_blank" rel="noopener noreferrer" class="">layout/iterator.rs</a>, we implemented the layout iterators. Some of the key points are</p>
<ul>
<li class="">Both col-major and row-major versions are written. Layout iteration is not iteration of a one-dimensional array; it can have different orders. For col-major iteration, since the first index changes most, the efficiency is somewhat higher; but this has not yet been proven with micro benchmarks. In the implementation of internal operators, we basically always use the col-major version.</li>
<li class="">The most performance-critical functions are <code>next_iter_index</code> and <code>back_iter_index</code>. They manually unroll 1-D – 4-D layouts, and use loops for the rest.</li>
<li class="">The RSTSR library allows fixed and variable dimensions. Iterators are much more efficient under fixed dimensions, possibly because under static dimensions shape is implemented with <code>[usize; N]</code>, while under dynamic dimensions it is implemented with <code>Vec&lt;usize&gt;</code>. At compile time, <code>[usize; N]</code> is friendlier to the compiler's performance optimization.</li>
<li class="">Iterators are frequent operations and need high efficiency; in <code>next_iter_index</code> and <code>back_iter_index</code>, the changes to the internal variables <code>index_start</code> and <code>index_end</code> of the iterator need to be in-place, and cannot clone one out.</li>
</ul>
<p>In the file <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/feature_rayon/layout_par_iter.rs" target="_blank" rel="noopener noreferrer" class="">feature_rayon/layout_par_iter.rs</a>, we implemented the parallel layout iterators. This is basically just applying the formula. Note that</p>
<ul>
<li class="">I guess that only by implementing <code>IndexedParallelIterator</code> can Rayon's parallel efficiency approach OpenMP.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="84-how-are-elementwise-tensor-operators-implemented">8.4. How Are Elementwise Tensor Operators Implemented?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#84-how-are-elementwise-tensor-operators-implemented" class="hash-link" aria-label="Direct link to 8.4. How Are Elementwise Tensor Operators Implemented?" title="Direct link to 8.4. How Are Elementwise Tensor Operators Implemented?" translate="no">​</a></h3>
<p>Elementwise tensor operations include the four arithmetic operations and common functions (like sqrt, sin, etc.).</p>
<p>For the four arithmetic operations, they are mentioned in section 3.6 (pp 15–20) of the RSTSR 1st report.</p>
<p>Here we take another, more intuitive sin function implementation as an example.</p>
<ul>
<li class="">
<p>RSTSR's operators separate frontend and backend as much as possible; specifically, the Tensor trait part, the Device trait part, and the concrete Device impl part.</p>
</li>
<li class="">
<p>RSTSR's trait definitions generally have the <code>API</code> suffix, to distinguish them from struct types.</p>
</li>
<li class="">
<p>The implementation of the sin function in the Tensor trait part is in <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/tensor/operators/op_unary_common.rs#L64" target="_blank" rel="noopener noreferrer" class="">tensor/operators/op_unary_common.rs</a>. The sin function takes a single-variable input, so it is called a unary function. Since we need to implement many unary functions (like sqrt, log, etc.), macro_rules needs to be used. The trait in the Tensor part should guarantee that any backend can execute it; that is, it really only designs the interface and simple execution logic here, and the real computation should not appear here.</p>
</li>
<li class="">
<p>The Device trait part is a pure interface. The trait declaration of the sin function is in <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/storage/operators/op_binary_common.rs" target="_blank" rel="noopener noreferrer" class="">storage/operators/op_binary_common.rs</a>. Because the sin function involves an input tensor and an output tensor, there are two parameters involved; we call it a binary function (this naming convention is probably not good, and can be changed later).</p>
</li>
<li class="">
<p>Taking <code>DeviceCpuSerial</code> as an example, the Device impl is in <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/device_cpu_serial/operators/op_binary_common.rs" target="_blank" rel="noopener noreferrer" class="">device_cpu_serial/operators/op_binary_common.rs</a>. We notice that what is actually done here is</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">impl</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">...</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token class-name">DeviceSinAPI</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">...</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token class-name">DeviceCpuSerial</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">op_muta_refb</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">op_muta_refb_func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token closure-params">a</span><span class="token closure-params punctuation" style="color:#393A34">,</span><span class="token closure-params"> b</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">sin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>This involves a function <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/device_cpu_serial/operators/op_with_func.rs#L275-L292" target="_blank" rel="noopener noreferrer" class=""><code>op_muta_refb_func</code></a>, which will go to the code <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/device_cpu_serial/operators/op_with_func.rs#L120-L152" target="_blank" rel="noopener noreferrer" class=""><code>op_muta_refb_func_cpu_serial</code></a> that actually does the computation. This function reads the input tensor's raw data <code>b: &amp;[TB]</code> and layout <code>lb: &amp;Layout&lt;D&gt;</code>, the output tensor's raw data <code>a: &amp;mut [TA]</code> and layout <code>la: &amp;Layout&lt;D&gt;</code>, and the mapping function <code>f: impl FnMut</code> between them (in the current example, the sin function). This is done to simplify the code, because unary functions all have a unified implementation strategy.</p>
</li>
<li class="">
<p>In the concrete computation code, we call the function <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/layout/rearrangement.rs#L237" target="_blank" rel="noopener noreferrer" class=""><code>translate_to_col_major</code></a>. Its purpose is,</p>
<ul>
<li class="">if the input is a col-major tensor, we iterate in col-major;</li>
<li class="">if the input is a tensor of another major, then we transpose it to col-major for iteration. Users only care that the output is correct, so we do not necessarily have to follow the tensor's original iteration order.</li>
</ul>
</li>
<li class="">
<p>Later, <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/layout/rearrangement.rs#L311" target="_blank" rel="noopener noreferrer" class=""><code>translate_to_col_major_with_contig</code></a> is called once more, whose purpose is</p>
<ul>
<li class="">to extract the largest contiguous dimension length. When a tensor has at least one dimension contiguous in memory, we merge all these contiguous dimensions together, and pack the remaining non-contiguous dimensions into one block. For example,<!-- -->
<ul>
<li class="">if the 3-d tensor <code>a</code> is declared in contiguous memory, then the largest contiguous dimension length is the whole tensor size, with no remaining non-contiguous dimensions;</li>
<li class="">for the above tensor <code>a</code>, taking the slice <code>a[1:4, :, :]</code>, it is globally contiguous just like before;</li>
<li class="">taking the slice <code>a[:, 1:4, :]</code>, it has one non-contiguous dimension, and the largest contiguous dimension length is the product of the last 2 dimensions;</li>
<li class="">taking the slice <code>a[::-1, ::-1, ::-1]</code>, it is reversely contiguous; in this case we consider it completely non-contiguous.</li>
</ul>
</li>
<li class="">when memory is contiguous, using the standard library's built-in contiguous iterator is the fastest; for simple four-arithmetic binary problems, the contiguous parallel iterator may not be as efficient as the contiguous serial iterator; using layout iterators only drags down the speed.</li>
<li class="">the remaining part uses layout iterators.</li>
</ul>
</li>
</ul>
<p>In summary,</p>
<ul>
<li class="">The Tensor and Device traits are used to define operations; this is the core design of the tensor library (but other users should also be able to implement them, and in the future these operations may be separated from the rstsr-core core library); these parts are not responsible for computation, only for interfaces.</li>
<li class="">The Device impl part can be done by users themselves; they can do any high-performance implementation inside.</li>
</ul>
<p>This idea can be considered modeled after the burn library, but no reference was made to their code.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="85-are-transpose-and-reshape-operators">8.5. Are Transpose and Reshape Operators?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#85-are-transpose-and-reshape-operators" class="hash-link" aria-label="Direct link to 8.5. Are Transpose and Reshape Operators?" title="Direct link to 8.5. Are Transpose and Reshape Operators?" translate="no">​</a></h3>
<p>No. They are counted as Tensor manipulation.</p>
<p>Not all tensor operations are classified as operators.</p>
<ul>
<li class="">Some cases are combined operators, like <code>exp(x) - 1</code>. Depending on the situation, this combined operator is implemented as a standalone operator (for higher floating point precision or higher performance), or can be naively implemented as <code>exp(x) - 1</code>.</li>
<li class="">Transpose is indeed not an operator. A Tensor is divided into the concrete data part (storage) and the layout; transpose only handles the layout. The interface at the Tensor level is defined in the <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/tensor/manuplication.rs#L387-L400" target="_blank" rel="noopener noreferrer" class=""><code>into_transpose_f</code></a> function, while the program that concretely does the layout-level transpose is <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/layout/layoutbase.rs#L434-L470" target="_blank" rel="noopener noreferrer" class=""><code>Layout::transpose</code></a>.</li>
<li class="">Reshape is indeed somewhat special, because it may not need to allocate new memory to store the tensor, but may also need to. Following ndarray's approach, we implement the <code>TensorCow</code> type; if new memory indeed needs to be allocated, we need to use the operator empty (<code>empty_impl</code>) to declare a block of memory, and use the assignment operator (<code>assign_arbitary</code>) to copy the original tensor into the new tensor. The reshape function is actually implemented in the program <a href="https://github.com/ajz34/rstsr/blob/21a8e0aeeec5ca76a8f3283ce86886f3ab3d28e1/rstsr-core/src/tensor/manuplication.rs#L1080-L1151" target="_blank" rel="noopener noreferrer" class=""><code>change_shape_f</code></a>; but on the one hand this function can still be optimized, and on the other hand it seems too complex in logic and should be separated into the layout part.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="86-how-to-control-the-number-of-blas-threads">8.6. How to Control the Number of BLAS Threads?<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-second-report#86-how-to-control-the-number-of-blas-threads" class="hash-link" aria-label="Direct link to 8.6. How to Control the Number of BLAS Threads?" title="Direct link to 8.6. How to Control the Number of BLAS Threads?" translate="no">​</a></h3>
<p>RSTSR learned from rest_tensors in this respect; that is, <code>openblas_set_num_threads</code> is used to control the number of threads:</p>
<ul>
<li class="">when in a Rayon parallel region (when <code>rayon::current_thread_index</code> returns a value), single-threaded BLAS is used;</li>
<li class="">when in a serial region (when <code>rayon::current_thread_index</code> returns None), multi-threaded BLAS is restored;</li>
</ul>
<p>This may not be the best solution, but it should be enough for us.</p>
<p>Not the most urgent problem, but doing this has other detailed issues:</p>
<ul>
<li class="">the above implementation strategy seems to work only with OpenBLAS compiled with pthread; it causes problems with OpenBLAS compiled with OpenMP;</li>
<li class="">this function is OpenBLAS-specific and cannot be used when linking MKL or BLIS. Using this function means binding to OpenBLAS.</li>
</ul>
<p>I think in C/C++, this kind of problem can be solved by defining precompilation macros in header files (like <code>#if(HAVE_OPENBLAS)</code>), and using precompilation judgments to switch between MKL and OpenBLAS in actual use. Such an approach is not impossible in Rust, but I think there is another way: design two sets of backends, <code>DeviceOpenBLAS</code> and <code>DeviceMKL</code>. The two sets of backends use two different thread control strategies. In electronic structure programs, then define through precompilation macros (cargo features in Rust) whether the default <code>DeviceBLAS</code> is <code>DeviceOpenBLAS</code> or <code>DeviceMKL</code>.</p>]]></content>
        <author>
            <name>Andrew J. Zhu (祝震予)</name>
            <uri>https://github.com/ajz34</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[RSTSR 1st Report]]></title>
        <id>https://restgroup.github.io/rstsr-book/blog/rstsr-first-report</id>
        <link href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report"/>
        <updated>2024-09-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[RSTSR program draft: a Rust high-dimensional tensor data structure processing program built on the Python Array API]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="rstsr-draft-of-a-rust-high-dimensional-tensor-data-structure-processing-program-built-on-the-python-array-api">RSTSR: Draft of a Rust High-Dimensional Tensor Data Structure Processing Program Built on the Python Array API<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#rstsr-draft-of-a-rust-high-dimensional-tensor-data-structure-processing-program-built-on-the-python-array-api" class="hash-link" aria-label="Direct link to RSTSR: Draft of a Rust High-Dimensional Tensor Data Structure Processing Program Built on the Python Array API" title="Direct link to RSTSR: Draft of a Rust High-Dimensional Tensor Data Structure Processing Program Built on the Python Array API" translate="no">​</a></h2>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="abstract">Abstract<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#abstract" class="hash-link" aria-label="Direct link to Abstract" title="Direct link to Abstract" translate="no">​</a></h2>
<p>When writing scientific computing programs, the data storage structure and how to use that data structure for efficient computation are important and fundamental problems that need to be planned early. Today, NumPy and PyTorch have almost become the de facto standards for high-dimensional tensor data structures; the latter also provides a relatively unified interface for heterogeneous programming. But outside Python, except for the LibTorch library in C++, few languages support both high-dimensional tensors and heterogeneous programming. We hope the RSTSR program can resolve this dilemma in the Rust language in the future. The current RSTSR program is based on the Python Array API standard (a subset of the NumPy API), and has correctly implemented some important high-dimensional tensor operations and manipulations, exposing part of the interface in preparation for high-performance CPU computation and GPU computation. But for the goal of reimplementing most computational chemistry concerns on CPU, the current progress still needs 5–10 weeks; CUDA support may need even more time and effort. This document will 1) briefly analyze the current state of existing matrix or tensor libraries; 2) explain the practical significance and goals of the Rust tensor library RSTSR; 3) provide technical details on the features already implemented in RSTSR.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>This document was transcribed from the original typst report to mdx format by AI. The transcription was performed by Deepseek-v4-flash.<br><strong>This document is an early document and does not reflect the current RSTSR design architecture or usage.</strong></p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-analysis-of-the-current-state-of-matrix-or-tensor-libraries">1. Analysis of the Current State of Matrix or Tensor Libraries<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#1-analysis-of-the-current-state-of-matrix-or-tensor-libraries" class="hash-link" aria-label="Direct link to 1. Analysis of the Current State of Matrix or Tensor Libraries" title="Direct link to 1. Analysis of the Current State of Matrix or Tensor Libraries" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="11-matrix-or-tensor-libraries-used-by-computational-chemistry-programs">1.1. Matrix or Tensor Libraries Used by Computational Chemistry Programs<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#11-matrix-or-tensor-libraries-used-by-computational-chemistry-programs" class="hash-link" aria-label="Direct link to 1.1. Matrix or Tensor Libraries Used by Computational Chemistry Programs" title="Direct link to 1.1. Matrix or Tensor Libraries Used by Computational Chemistry Programs" translate="no">​</a></h3>
<p>We write tensor libraries, which could be a contribution to the scientific computing community, or even to machine learning and visual rendering communities; but in the final analysis, our goal is still to serve computational chemistry programs. To that end, let us briefly review the matrix or tensor libraries used in computational chemistry.</p>
<table><thead><tr><th>Quantum chemistry software</th><th>Tensor or modern library</th><th>Development status</th></tr></thead><tbody><tr><td>Q-Chem</td><td>libtensor</td><td>Team-developed, tensor contraction and symmetrization, <a href="https://github.com/epifanovsky/libtensor" target="_blank" rel="noopener noreferrer" class="">open-source</a></td></tr><tr><td></td><td>liblas</td><td>BLAS/cuBLAS wrapper</td></tr><tr><td></td><td>libmathtools</td><td>Team-developed, early matrix/tensor library</td></tr><tr><td>PySCF</td><td>NumPy</td><td>External library, matrix/tensor scaling, matrix multiplication</td></tr><tr><td></td><td>SciPy</td><td>External library, matrix linear algebra</td></tr><tr><td></td><td><code>np_helper</code></td><td>Developed by the library author, supplements NumPy functionality, <a href="https://github.com/pyscf/pyscf/tree/master/pyscf/lib/np_helper" target="_blank" rel="noopener noreferrer" class="">open-source</a></td></tr><tr><td></td><td>TBLIS</td><td>External library, tensor contraction, <a href="https://github.com/devinamatthews/tblis" target="_blank" rel="noopener noreferrer" class="">open-source</a></td></tr><tr><td>Psi4</td><td>libmints/matrix</td><td>Team-developed, matrix operations, <a href="https://github.com/psi4/psi4/blob/7bfb86a14500e1fb757d91ab799e05163575921b/psi4/src/psi4/libmints/matrix.cc" target="_blank" rel="noopener noreferrer" class="">open-source</a></td></tr><tr><td>Psi4NumPy</td><td>opt_einsum, NumPy</td><td>Developed by the library author, tensor contraction, <a href="https://github.com/dgasmith/opt_einsum" target="_blank" rel="noopener noreferrer" class="">open-source</a></td></tr><tr><td>MPQC</td><td>MADNESS</td><td>Team-developed, tensor contraction and differential equations, <a href="https://github.com/m-a-d-n-e-s-s/madness" target="_blank" rel="noopener noreferrer" class="">open-source</a></td></tr></tbody></table>
<p>This table only shows that a rough program survey was carried out, and does not necessarily prove anything:</p>
<ul>
<li class="">Q-Chem spans a very long development history, developed from the 95's to today, with many old but still usable programs (e.g., <code>ccman</code>), and also <code>libtensor</code>, a fully-featured tensor library developed in modern C++ (e.g., <code>ccman2</code>); different programs use completely different tensor or linear algebra libraries, with no unified programming standard and a large variance in code quality.</li>
<li class="">PySCF did not deeply optimize for efficiency and large-system algorithms at its design time, but can achieve efficient implementations on small systems. This can be done through Python/C bindings, splitting performance-critical bottlenecks out of Python into C implementations. In fact, in my RI-MP2 polarizability calculation work, I used a similar technique.</li>
<li class="">Psi4 put considerable effort into NumPy performance improvements and tensor contraction standards, but this work was not really brought into Psi4's C++ main program; instead it derived from the Psi4NumPy teaching project. Psi4 is indeed very efficient, but it has no unified tensor library; rather, it handles tensor contraction problems separately in specific tasks (e.g., <code>occ</code>).</li>
<li class="">MPQC is probably a computational chemistry program that has in fact ended maintenance; it is not a successful project. But E. Valeev is still actively developing libint and TiledArray.</li>
<li class="">CP2K once independently developed libsmm, but later gave way to Intel's <a href="https://github.com/libxsmm/libxsmm" target="_blank" rel="noopener noreferrer" class="">libxsmm</a>. The latter can be used not only for DFT calculations, but is also an important implementation tool for CNN-representative machine learning methods on CPU.</li>
<li class="">There are many programs I do not know well, especially those that use MPI at scale (e.g., FHI-Aims, ORCA, VASP) or GPUs (e.g., TerraChem).</li>
</ul>
<p>But the commonality among them is,</p>
<ul>
<li class="">almost all successful modern computational chemistry programs have strong support for tensor computation.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="12-pyscfs-usage-characteristics-and-their-inspiration-for-rust-program-development">1.2. PySCF's Usage Characteristics and Their Inspiration for Rust Program Development<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#12-pyscfs-usage-characteristics-and-their-inspiration-for-rust-program-development" class="hash-link" aria-label="Direct link to 1.2. PySCF's Usage Characteristics and Their Inspiration for Rust Program Development" title="Direct link to 1.2. PySCF's Usage Characteristics and Their Inspiration for Rust Program Development" translate="no">​</a></h3>
<p>Every computational chemistry program has its own character; no computational chemistry program truly agrees on how to use math libraries (of course, disagreement also covers program structure and interfaces, input/output file formats, algorithms, etc.).</p>
<p>Perhaps the most successful molecular computational chemistry program today is ORCA, but this may be attributed to</p>
<ul>
<li class="">its forum-style community maintenance;</li>
<li class="">its complete program manual and relatively few program bugs;</li>
<li class="">its functionality that is relatively complete compared to Gaussian, with considerable performance improvement;</li>
<li class="">its free usage and convenient installation strategy, and multi-platform availability.</li>
</ul>
<p>But from a developer's perspective, ORCA is far from a good choice, especially due to its closed-source nature. Among open-source programs, the most successful today is PySCF. Its success is of course partly due to the PySCF developers' own characteristics:</p>
<ul>
<li class="">a clear strategy of separating code logic (Python) from performance-critical code (C);</li>
<li class="">usability-oriented design (not performance-oriented or system-size-capacity-oriented);</li>
<li class="">a breakthrough in designing the computational chemistry program as a library rather than a main-program-driven control flow; this is crucial for computational chemistry method developers, and also convenient for users with high customization needs in computation processes;</li>
<li class="">flexible use of object-oriented and functional programming features, prioritizing interface usability and avoiding complex inheritance;</li>
</ul>
<p>But many of its features are not the result of the PySCF developers' work, but rather of their choices:</p>
<ul>
<li class="">NumPy is almost the standard for medium-scale dense tensor computation (larger than the matrices in machine learning, game engines, and rendering tasks, but not requiring cross-node parallelism), which lowers developers' learning cost, and its code is easy to write and highly readable;</li>
<li class="">Python as a scripting language can run and debug immediately, without spending lots of time compiling and troubleshooting.</li>
</ul>
<p>When we choose Rust for development, we inevitably give up some of PySCF's advantages, especially Python's advantages as a scripting language; but what we hope to gain (or can gain) in exchange is</p>
<ul>
<li class="">program execution efficiency;</li>
<li class="">program stability and lower memory overhead (avoiding memory leaks caused by programming or the language itself);</li>
<li class="">binaries that are easier to distribute;</li>
<li class="">less FFI (cross-language interaction), and more convenient cross-platform (cross-OS) support;</li>
</ul>
<p>Relative to C++ and other languages, Rust also has greater advantages in engineering standards and deployment:</p>
<ul>
<li class="">Cargo's convenient build, test, rustfmt style, clippy code standards, tarpaulin coverage, and precompilation feature options; though documentation (doc) may be Cargo's current weakness;</li>
<li class="">thanks to Rust's strict code standards, as long as compilation produces no errors, we can safely handle complex lifetime and trait combinations.</li>
</ul>
<p>Correspondingly, the advantages of other languages that Rust inevitably gives up (which may also be disadvantages) include:</p>
<ul>
<li class="">Rust is not a scripting language; whether or not there is a Jupyter development environment (<a href="https://github.com/evcxr/evcxr" target="_blank" rel="noopener noreferrer" class="">evcxr</a>), this is definitely inconvenient;</li>
<li class="">Rust does not support template specialization as freely as C++, which can standardize code, but also makes lazy evaluation and type inference requiring compile-time computation difficult.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="13-numpys-characteristics-and-their-relevance-to-computational-chemistry">1.3. NumPy's Characteristics and Their Relevance to Computational Chemistry<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#13-numpys-characteristics-and-their-relevance-to-computational-chemistry" class="hash-link" aria-label="Direct link to 1.3. NumPy's Characteristics and Their Relevance to Computational Chemistry" title="Direct link to 1.3. NumPy's Characteristics and Their Relevance to Computational Chemistry" translate="no">​</a></h3>
<p>In my view, PySCF's success is not only due to its developers' own efforts, but also to riding the tailwind of Python and NumPy. We can use concrete examples to show NumPy's applications in computational chemistry; and thereby reflect on what expectations, as program developers, we might actually have of math libraries.</p>
<ol>
<li class="">
<p>High-dimensional tensors</p>
<p>These are frequently used in computational chemistry, especially in algorithms involving CC methods.</p>
</li>
<li class="">
<p>Broadcasting</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msubsup><mi mathvariant="normal">Δ</mi><mrow><mi>i</mi><mi>j</mi></mrow><mrow><mi>a</mi><mi>b</mi></mrow></msubsup><mo>=</mo><msub><mi>ϵ</mi><mi>i</mi></msub><mo>+</mo><msub><mi>ϵ</mi><mi>j</mi></msub><mo>−</mo><msub><mi>ϵ</mi><mi>a</mi></msub><mo>−</mo><msub><mi>ϵ</mi><mi>b</mi></msub></mrow><annotation encoding="application/x-tex">\Delta_{ij}^{ab} = \epsilon_i + \epsilon_j - \epsilon_a - \epsilon_b</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2822em;vertical-align:-0.3831em"></span><span class="mord"><span class="mord">Δ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-2.453em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">ij</span></span></span></span><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3831em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.7333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal">ϵ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.8694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal">ϵ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.7333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal">ϵ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal">ϵ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span></span>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">D </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> eo</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> eo</span><span class="token punctuation" style="color:#393A34">[</span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> ev</span><span class="token punctuation" style="color:#393A34">[</span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> ev</span><span class="token punctuation" style="color:#393A34">[</span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>This code may not actually be used in real MP2 energy calculations, because it has large memory requirements. But MP2 can be implemented in Python in three lines of code; when performance is not the critical part, such code is very intuitive. Similarly, in Laplace-Transform OS-MP2, we also use multiplicative Broadcasting:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi mathvariant="script">G</mi><mrow><mi>g</mi><mi>i</mi><mi>a</mi></mrow></msub><mo>=</mo><msup><mi>e</mi><mrow><msubsup><mi>D</mi><mi>i</mi><mi>a</mi></msubsup><msub><mi>t</mi><mi>g</mi></msub></mrow></msup></mrow><annotation encoding="application/x-tex">\mathcal{G}_{gia} = e^{D_i^a t_g}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathcal" style="margin-right:0.0593em">G</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0593em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span><span class="mord mathnormal mtight">ia</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.93em"></span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.93em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0278em">D</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7385em"><span style="top:-2.214em;margin-left:-0.0278em;margin-right:0.0714em"><span class="pstrut" style="height:2.5em"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight">i</span></span></span><span style="top:-2.931em;margin-right:0.0714em"><span class="pstrut" style="height:2.5em"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286em"><span></span></span></span></span></span></span><span class="mord mtight"><span class="mord mathnormal mtight">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1645em"><span style="top:-2.357em;margin-left:0em;margin-right:0.0714em"><span class="pstrut" style="height:2.5em"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2819em"><span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">grid_exp </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">exp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">D_ia </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> grid_points</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>Similar situations are also common in DFT grid integration.</p>
</li>
<li class="">
<p>Dimensional transformation under contiguous memory</p>
<p>Although the following problems can be implemented with Einstein summation / einops, einops should in principle satisfy the following computational requirements. But efficient einops implementations are difficult and require substantial effort; without einops, the best approach is to reshape the dimensions and then do matrix multiplication:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mtable rowspacing="0.25em" columnalign="right left" columnspacing="0em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msubsup><mi>D</mi><mrow><mi>j</mi><mi>k</mi></mrow><mrow><mo stretchy="false">(</mo><mn>2</mn><mo stretchy="false">)</mo></mrow></msubsup></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mrow><mi>b</mi><mi>i</mi><mi>a</mi></mrow></munder><mo>−</mo><mn>2</mn><msub><mi>T</mi><mrow><mi>j</mi><mi>b</mi><mo separator="true">,</mo><mi>i</mi><mi>a</mi></mrow></msub><msub><mi>t</mi><mrow><mi>k</mi><mi>b</mi><mo separator="true">,</mo><mi>i</mi><mi>a</mi></mrow></msub></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msubsup><mi>D</mi><mrow><mi>a</mi><mi>b</mi></mrow><mrow><mo stretchy="false">(</mo><mn>2</mn><mo stretchy="false">)</mo></mrow></msubsup></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mrow><mi>j</mi><mi>c</mi><mi>i</mi></mrow></munder><mn>2</mn><msub><mi>T</mi><mrow><mi>j</mi><mi>c</mi><mo separator="true">,</mo><mi>i</mi><mi>a</mi></mrow></msub><msub><mi>t</mi><mrow><mi>j</mi><mi>c</mi><mo separator="true">,</mo><mi>i</mi><mi>b</mi></mrow></msub></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><msub><mi mathvariant="normal">Γ</mi><mrow><mi>P</mi><mo separator="true">,</mo><mi>i</mi><mi>a</mi></mrow></msub></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mrow><mi>j</mi><mi>b</mi></mrow></munder><msub><mi>Y</mi><mrow><mi>P</mi><mo separator="true">,</mo><mi>j</mi><mi>b</mi></mrow></msub><msub><mi>T</mi><mrow><mi>j</mi><mi>b</mi><mo separator="true">,</mo><mi>i</mi><mi>a</mi></mrow></msub></mrow></mstyle></mtd></mtr></mtable><annotation encoding="application/x-tex">\begin{aligned}
D_{jk}^{(2)} &amp;= \sum_{bia} -2 T_{jb,ia} t_{kb,ia} \\
D_{ab}^{(2)} &amp;= \sum_{jci} 2 T_{jc,ia} t_{jc,ib} \\
\Gamma_{P,ia} &amp;= \sum_{jb} Y_{P,jb} T_{jb,ia}
\end{aligned}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:7.9041em;vertical-align:-3.7021em"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:4.2021em"><span style="top:-6.2021em"><span class="pstrut" style="height:3.05em"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.0278em">D</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0278em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">2</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.4374em"><span></span></span></span></span></span></span></span></span><span style="top:-3.5499em"><span class="pstrut" style="height:3.05em"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.0278em">D</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0448em"><span style="top:-2.3987em;margin-left:-0.0278em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ab</span></span></span></span><span style="top:-3.2198em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">2</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3013em"><span></span></span></span></span></span></span></span></span><span style="top:-0.7862em"><span class="pstrut" style="height:3.05em"></span><span class="mord"><span class="mord"><span class="mord">Γ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight">ia</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:3.7021em"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:4.2021em"><span style="top:-6.2021em"><span class="pstrut" style="height:3.05em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8479em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">bia</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord">−</span><span class="mord">2</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">b</span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight">ia</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em">k</span><span class="mord mathnormal mtight">b</span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight">ia</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span><span style="top:-3.5499em"><span class="pstrut" style="height:3.05em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8723em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">i</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4138em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord">2</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">c</span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight">ia</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">c</span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight">ib</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span><span style="top:-0.7862em"><span class="pstrut" style="height:3.05em"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.8479em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">b</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4382em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.2222em">Y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.2222em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">b</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em">j</span><span class="mord mathnormal mtight">b</span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight">ia</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:3.7021em"><span></span></span></span></span></span></span></span></span></span></span></span>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> t </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">tsr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">reshape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nocc</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nocc </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> nvir</span><span class="token operator" style="color:#393A34">**</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> tsr </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rdm2</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">so</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> so</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> T @ t</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">T</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> t </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">tsr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">reshape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nocc</span><span class="token operator" style="color:#393A34">**</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> nvir</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nvir</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> tsr </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rdm2</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">sv</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sv</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain">  </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> T</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">T @ T</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">T </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> T</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">reshape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nocc </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> nvir</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nocc </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> nvir</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Gamma </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Y @ T</span><br></div></code></pre></div></div>
<p>The <code>np.reshape</code> above needs to transform the 4-d tensors into 2-d matrices, and should not involve memory copies.</p>
</li>
<li class="">
<p>Einstein summation / einops</p>
<p>Still for the above problems, using einops would be much more convenient:</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">rdm2</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">so</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> so</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">einsum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"jbia, kbia -&gt; jk"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rdm2</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">sv</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sv</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain">  </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">einsum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"jcia, jcib -&gt; ab"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Gamma </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">einsum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Pjb, jbia -&gt; Pia"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Y</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> T</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>Although the above code is MP2 gradient-related code, similar code is common in the CC computation modules of MPQC, Q-Chem, and PySCF.</p>
<p>For example Q-Chem:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// ccman2/ccman2/cs_cc/cs_ccsd_pt.C</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">contract</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">d</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">t2a_re</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">c</span><span class="token operator" style="color:#393A34">|</span><span class="token plain">d</span><span class="token operator" style="color:#393A34">|</span><span class="token plain">i</span><span class="token operator" style="color:#393A34">|</span><span class="token plain">j</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">i_vvov_re</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token operator" style="color:#393A34">|</span><span class="token plain">b</span><span class="token operator" style="color:#393A34">|</span><span class="token plain">k</span><span class="token operator" style="color:#393A34">|</span><span class="token plain">d</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>For example <a href="https://github.com/ValeevGroup/mpqc/blob/master/src/mpqc/chemistry/qc/lcao/cc/ccsd.h" target="_blank" rel="noopener noreferrer" class="">MPQC</a>:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// ccsd.h, line 342</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">tau</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"a,b,i,j"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">t2</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"a,b,i,j"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">t1</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"a,i"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">t1</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"b,j"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>Even code this intuitive, if combined with an efficient einops, can reach considerable efficiency; but einops is not an easy library to write.</p>
</li>
</ol>
<p>NumPy also has some difficult-to-handle problems; in PySCF, some computation processes must rely on C implementations, and problems that are difficult to implement efficiently in Python unless using numba, including</p>
<ol>
<li class="">matrix transposition involving memory copies;</li>
<li class="">manual parallelization and triangular matrix multiplication (e.g., AO2MO computation).</li>
</ol>
<p>Some of these problems are inherent to NumPy itself, and some are Python language problems.</p>
<p>Overall, in computational chemistry, we need matrix multiplication functionality, but we also have substantial needs for the high-dimensional tensor features supported by NumPy and its distinctive features.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="14-the-python-array-api-and-existing-matrixtensor-libraries">1.4. The Python Array API and Existing Matrix/Tensor Libraries<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#14-the-python-array-api-and-existing-matrixtensor-libraries" class="hash-link" aria-label="Direct link to 1.4. The Python Array API and Existing Matrix/Tensor Libraries" title="Direct link to 1.4. The Python Array API and Existing Matrix/Tensor Libraries" translate="no">​</a></h3>
<p>NumPy not only interfaces with the functionality needed by computational chemistry, but the convenience of its API is also crucial. In the 10's, NumPy had already become Python's de facto numerical computation program; during the explosive growth of machine learning in the 15'–20's, amid the development and competition of TensorFlow, MXNet, PyTorch and other libraries, in my view, PyTorch's current success is largely because its API is very close to NumPy, making it easy for beginners, avoiding high learning costs, and reducing the communication cost between libraries.</p>
<p>The authors of Python math libraries also realized the importance of API interfaces. In 2020, a community group discussed the interface forms of Python math libraries and, based on NumPy and other popular math libraries, defined the API interfaces that math libraries must satisfy, in the form of the <a href="https://data-apis.org/" target="_blank" rel="noopener noreferrer" class="">Python Array API Standard</a> (after NumPy 2.0, the Python Array API Standard is a true subset of the NumPy API).</p>
<p>Although the Python Array API is a Python interface, other languages were also considered in its design; C++ and Rust, among others, can also follow the rules of this interface to a certain extent for program development. I personally also hope that the library we develop will take the Python Array API into account as much as possible.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="141-the-python-array-api-and-its-related-math-libraries">1.4.1. The Python Array API and Its Related Math Libraries<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#141-the-python-array-api-and-its-related-math-libraries" class="hash-link" aria-label="Direct link to 1.4.1. The Python Array API and Its Related Math Libraries" title="Direct link to 1.4.1. The Python Array API and Its Related Math Libraries" translate="no">​</a></h4>
<p>Currently, the vast majority of successful math libraries have APIs close to NumPy, or are themselves libraries designed under NumPy's influence and inspiration.</p>
<table><thead><tr><th>API language</th><th>Math library</th><th>Platform</th><th>Distinctive features</th></tr></thead><tbody><tr><td>Python</td><td>NumPy</td><td>CPU</td><td>1. Fairly complete linear algebra functionality based on BLAS (<a href="https://numpy.org/doc/stable/reference/routines.linalg.html" target="_blank" rel="noopener noreferrer" class="">linalg</a>, <a href="https://numpy.org/doc/stable/reference/routines.fft.html" target="_blank" rel="noopener noreferrer" class="">fft</a>)<br>2. Can be extended to SciPy's rich linear algebra functionality<br>3. Advanced indexing (<a href="https://numpy.org/doc/stable/user/basics.indexing.html#advanced-indexing" target="_blank" rel="noopener noreferrer" class="">advanced indexing</a>)<br>4. More numerical math functionality (sparse, polynomial, statistics)</td></tr><tr><td>Python \ C++</td><td>PyTorch \ LibTorch</td><td>Multi-platform</td><td>1. Multi-platform/backend support (HPU/NPU/FPGA/RISC-V)<br>2. backward, computational-graph-based lazy evaluation</td></tr><tr><td>Python</td><td>JAX</td><td>CPU \ CUDA \ TPU</td><td>1. JIT-based, with performance gains for small-matrix tasks<br>2. backward, computational-graph-based lazy evaluation<br>3. Some degree of MPI support</td></tr><tr><td>Python</td><td>Paddle</td><td>Multi-platform</td><td>1. Supports most domestic GPUs<br>2. Supports distributed training</td></tr><tr><td>Python</td><td>CuPy</td><td>CUDA \ ROCm</td><td>1. Supports most of SciPy's linear algebra functionality<br>2. Relatively lightweight, easier to compile and install<br>3. Supports embedding CUDA code in Python, high flexibility</td></tr><tr><td>Python</td><td>DASK</td><td>MPI</td><td>1. Designed for multi-machine parallelism and processing large tensors<br>2. Has dedicated communication and queue modules (<a href="https://distributed.dask.org/en/stable/" target="_blank" rel="noopener noreferrer" class="">distributed</a>)</td></tr><tr><td>C++</td><td>XTensor</td><td>CPU</td><td>1. lazy evaluation</td></tr><tr><td>Rust</td><td>ndarray</td><td>CPU</td><td>1. Addresses <a href="https://data-apis.org/array-api/latest/design_topics/copies_views_and_mutation.html" target="_blank" rel="noopener noreferrer" class="">mutability</a> and <a href="https://data-apis.org/array-api/latest/API_specification/type_promotion.html" target="_blank" rel="noopener noreferrer" class="">data type promotion</a> at the language level</td></tr><tr><td>JavaScript</td><td>stdlib</td><td>CPU</td><td></td></tr><tr><td>Go</td><td>Gonum</td><td>CPU</td><td></td></tr></tbody></table>
<p>But it should also be pointed out that successful math libraries do not necessarily follow the Python Array API; this is also reflected in the Rust language, which we will supplement in the next subsection. For other languages,</p>
<ul>
<li class="">Fortran, Matlab, Julia and other languages natively support high-dimensional tensors, and partially support some math operations;</li>
<li class="">many Fortran, C/C++ programs directly use high-performance BLAS; not necessarily using external wrapper libraries or self-developed simple wrappers;</li>
<li class="">Eigen in C++ is somewhat special: it has strong lazy evaluation support and small-matrix computation performance; large-matrix performance is not bad. But it was developed in the 05's, developed early, and is hard to turn around.</li>
</ul>
<p>But in general, today's math library designs can usually express tensor types, and at the API level try to be as close to NumPy (or the Python array API standard) as possible.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="142-math-libraries-in-the-rust-language">1.4.2. Math Libraries in the Rust Language<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#142-math-libraries-in-the-rust-language" class="hash-link" aria-label="Direct link to 1.4.2. Math Libraries in the Rust Language" title="Direct link to 1.4.2. Math Libraries in the Rust Language" translate="no">​</a></h4>
<p>The math and machine learning libraries in the Rust ecosystem are quite diverse, but not all satisfy our needs. The table below briefly lists them.</p>
<table><thead><tr><th>Math library</th><th>Purpose</th><th>Maintenance status</th><th>Tensor</th><th>Reshape</th><th>Differentiable</th><th>GPU</th><th>Complex</th><th>Linear algebra</th></tr></thead><tbody><tr><td>ndarray</td><td>High-dimensional tensors</td><td>Not active</td><td>✔</td><td>✔</td><td></td><td><sup>1</sup></td><td>✔</td><td>✔<sup>2</sup></td></tr><tr><td>faer</td><td>High performance</td><td>Development</td><td></td><td></td><td></td><td></td><td>✔<sup>3</sup></td><td>✔<sup>4</sup></td></tr><tr><td>nalgebra</td><td>Linear algebra</td><td>Active</td><td></td><td></td><td></td><td></td><td>✔</td><td>✔</td></tr><tr><td>dfdx</td><td>AI backend</td><td>Not active</td><td>✔</td><td></td><td>✔</td><td>✔</td><td></td><td></td></tr><tr><td>candle</td><td>AI backend</td><td>Development</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td></td><td></td></tr><tr><td>burn</td><td>AI frontend</td><td>Development</td><td>✔<sup>5</sup></td><td>✔</td><td>✔</td><td>✔</td><td></td><td></td></tr><tr><td>sprs</td><td>Sparse matrix</td><td>Development</td><td></td><td></td><td></td><td></td><td>✔</td><td></td></tr></tbody></table>
<ol>
<li class="">ndarray is not expected to implement GPU support (<a href="https://github.com/rust-ndarray/ndarray/pull/1377" target="_blank" rel="noopener noreferrer" class="">ndarray #1377</a>).</li>
<li class="">ndarray's linear algebra is provided by the external library ndarray-linalg; the latter has stopped maintenance. But conversions between ndarray and faer, nalgebra are relatively easy; therefore, despite the fragmented ecosystem, solutions that handle both high-dimensional tensors and linear algebra still exist.</li>
<li class="">faer has strong complex number support, but it is essentially not a general matrix library but a high-performance computing library benchmarking against OpenBLAS, so it only implements common floating point types. The library author is aware of F16 and BF16, but they will not be introduced into faer in the short term (<a href="https://github.com/sarah-ek/faer-rs/issues/32" target="_blank" rel="noopener noreferrer" class="">faer-rs #32</a>).</li>
<li class="">faer currently supports fewer linear algebra functions, but has high performance.</li>
<li class="">burn does have high-dimensional tensors, but this is mainly for storing the tensors needed by machine learning. The library itself does not support strides, so tensors cannot be used for general computation.</li>
</ol>
<p>Besides these, einops, as a supporting library, also has important potential help for computational chemistry programs. The closest libraries in Rust are einops (serving tch-rs) and candle_einops (serving candle), i.e., these libraries mainly target machine learning applications.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-significance-and-goals-of-the-rust-tensor-library-rstsr">2. Significance and Goals of the Rust Tensor Library RSTSR<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#2-significance-and-goals-of-the-rust-tensor-library-rstsr" class="hash-link" aria-label="Direct link to 2. Significance and Goals of the Rust Tensor Library RSTSR" title="Direct link to 2. Significance and Goals of the Rust Tensor Library RSTSR" translate="no">​</a></h2>
<p>From the above discussion, I believe that the current Rust math libraries still lack something for today's computational chemistry programs. Developing a new math library may not be valuable in the short term, but it is necessary in the long term.</p>
<p>For this reason, I have tried to start the RSTSR program, and hope to invest time in this project. I hope such a program will aim to assist chemistry program development, while also accommodating existing tensor library standards and other possible scientific computing needs to a certain extent.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="21-breakdown-of-tensor-library-features">2.1. Breakdown of Tensor Library Features<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#21-breakdown-of-tensor-library-features" class="hash-link" aria-label="Direct link to 2.1. Breakdown of Tensor Library Features" title="Direct link to 2.1. Breakdown of Tensor Library Features" translate="no">​</a></h3>
<p>For computational chemistry, I think the functionality a math library must carry includes at least</p>
<ol>
<li class="">high-dimensional tensor data structures and their basic operations (Python array API standard);</li>
<li class="">basic linear algebra (matrix decomposition, eigenvalue problems) and FFT (if periodic systems are supported);</li>
<li class="">multithreading or other parallel modes (guaranteeing that at least 30% or more of the machine's floating point or bandwidth efficiency can be used);</li>
<li class="">complex number types, and preferably arbitrary types (especially arbitrary floating point precision types);</li>
</ol>
<p>The above characteristics are also (a subset of) NumPy's functionality. Many of these features also appear in the Rust library ndarray, but it is weak in linear algebra, and lacks the following important optional features.</p>
<p>The important optional features include:</p>
<ol start="5">
<li class="">advanced linear algebra (interpolation, quadratic convergence and solving, matrix function extrema, though not necessarily as a standalone math library);</li>
<li class="">einops (simplifying tensor computation code and unifying tensor multiplication implementations, but replaceable with basic matrix algebra);</li>
<li class="">GPU heterogeneity (devices with better cost-performance and faster computation);</li>
<li class="">special BLAS features (batched GEMM may be used for DMRG methods, BF16-based FP32 GEMM may be used for post-HF methods);</li>
</ol>
<p>Features of uncertain importance include:</p>
<ol start="9">
<li class="">MPI heterogeneity (depending on the technical path, it may be Dask-native support or Scalapack non-native support);<br>
Whether MPI matters depends on 1) whether the program's main parallel mode uses threads or processes, 2) whether the program focuses on large-scale parallelism; many computational chemistry programs have little multi-process support, yet are very successful;</li>
<li class="">small matrix multiplication (some DFT computation requirements);</li>
<li class="">symmetric tensor operations, tensor symmetrization/antisymmetrization (symmetry systems, CC algorithms);</li>
<li class="">general sparse matrix data structures and basic operations;</li>
<li class="">computational graphs and automatic differentiation (the most important feature of machine learning programs, but computational chemistry itself usually does not need it; if our program needs to interface with machine learning, this feature needs to be considered);</li>
</ol>
<p>Features that are not necessarily important include:</p>
<ol start="14">
<li class="">lazy evaluation (it is generally used in memory-bottleneck code, but matrix-multiplication-dominated problems are either not memory-bound, or can sacrifice a small amount of code elegance to guarantee efficiency; lazy evaluation is somewhat difficult to implement, which would bring great trouble to library maintenance and open-source collaboration).</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="22-goals-of-the-tensor-library-rstsr-and-expected-implementation-phases">2.2. Goals of the Tensor Library RSTSR and Expected Implementation Phases<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#22-goals-of-the-tensor-library-rstsr-and-expected-implementation-phases" class="hash-link" aria-label="Direct link to 2.2. Goals of the Tensor Library RSTSR and Expected Implementation Phases" title="Direct link to 2.2. Goals of the Tensor Library RSTSR and Expected Implementation Phases" translate="no">​</a></h3>
<p>In the tensor library RSTSR, we will focus on implementing high-dimensional tensor data structures and GPU heterogeneity. The work completed so far concentrates on high-dimensional tensor data structures and their basic operations:</p>
<ul>
<li class="">high-dimensional tensor data structures;</li>
<li class="">most Layout operations (tensor operations that do not change the underlying data);</li>
<li class="">Layout-based tensor element iterators (iterators decoupled from the underlying data);</li>
<li class="">broadcasting (matching rules for tensors of different dimensions);</li>
<li class="">for computation problems, separating backend implementations from frontend interfaces;</li>
<li class="">basic arithmetic operations on tensors (a fairly efficient single-threaded implementation);</li>
<li class="">tensor matrix multiplication (a correctness-first implementation; efficiency needs to be improved through future backends);</li>
<li class="">tensor creation and shape changes.</li>
</ul>
<p>These are preliminary works, and are not yet mature enough to be applied to the REST program.</p>
<p>If I could develop the RSTSR tensor library full-time, I think a suitable schedule would be:</p>
<ul>
<li class="">2–4 weeks to fully reproduce most of the functionality required by the Python array API (excluding linear algebra);</li>
<li class="">2–4 weeks to complete the parallel computation code, the BLAS/Lapack backend, and the faer backend;</li>
<li class="">2–3 weeks to implement the supplementary features in rest_tensor (including linear algebra);</li>
<li class="">4–8 weeks to implement the CUDA backend based on cudarc;</li>
<li class="">2–4 weeks to propose an MPI solution based on Scalapack (but not written as a library).</li>
</ul>
<p>In the above process, the first two steps need to be done first; the order of the subsequent steps can be shuffled. The total is about 3–5 months.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-rstsr-design-and-technical-details-of-implemented-features">3. RSTSR Design and Technical Details of Implemented Features<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#3-rstsr-design-and-technical-details-of-implemented-features" class="hash-link" aria-label="Direct link to 3. RSTSR Design and Technical Details of Implemented Features" title="Direct link to 3. RSTSR Design and Technical Details of Implemented Features" translate="no">​</a></h2>
<p>The Rust language usually clearly divides composite types into two parts: 1) data structures (struct) or interface traits (trait); 2) their implementations (impl). In general, implementations (impl) are easy to replace; but changes to data structures (struct) and interface traits (trait) easily lead to serious code refactoring.</p>
<p>Among the features listed in the "Breakdown of Tensor Library Features" section above, the ones that profoundly affect data structures and interface traits are:</p>
<ol>
<li class="">high-dimensional tensor data structures, and their basic operations;</li>
<li class="">GPU heterogeneity;</li>
<li class="">symmetric tensors;</li>
<li class="">computational graphs and automatic differentiation;</li>
<li class="">lazy evaluation.</li>
</ol>
<p>The other features are relatively independent and will not significantly affect the tone of the program design, except:
9. MPI heterogeneity: whether or not the native-support path is adopted, MPI heterogeneity cannot be implemented directly on a standalone high-dimensional tensor; it will inevitably split a single large high-dimensional tensor into small pieces; therefore, MPI heterogeneity must be built on top of well-developed high-dimensional tensor data;
12. sparse matrices: they differ too much from high-dimensional tensors, and would generally use a data structure different from that of high-dimensional tensors.</p>
<p>RSTSR currently only considers high-dimensional tensors and future GPU programs. Although we call GPU "heterogeneous" here, we currently only regard it as a backend different from CPU. In fact, when we also treat BLAS and faer as two tensor computation backends, then high-performance CPU libraries themselves are backends, implemented in the same way as future GPU implementations. Therefore, multi-backend implementation should also be considered early.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="31-abandoned-feature-automatic-differentiation-and-lazy-evaluation">3.1. Abandoned Feature: Automatic Differentiation and Lazy Evaluation<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#31-abandoned-feature-automatic-differentiation-and-lazy-evaluation" class="hash-link" aria-label="Direct link to 3.1. Abandoned Feature: Automatic Differentiation and Lazy Evaluation" title="Direct link to 3.1. Abandoned Feature: Automatic Differentiation and Lazy Evaluation" translate="no">​</a></h3>
<p>Automatic differentiation requires computational graph functionality. This type of feature has at least two core difficulties:</p>
<ul>
<li class="">expression trees;</li>
<li class="">variable ownership.</li>
</ul>
<p>Expression trees are somewhat difficult to implement. They are essentially lazy evaluation as well, and can implement asynchronous computation (CUDA stream computation) within this framework, and can also simplify computation flows (e.g., <code>c += 2 * a</code> simplified to <code>famdd(c, 2, a)</code>). But they are not a common data structure in scientific computing. Implementing their inplace operation rules is difficult; even PyTorch frequently had inplace operation bugs in its early days.</p>
<p>At the same time, as Rust is a language with very strict variable lifetimes, tree-structured implementations are indeed difficult. In fact, when implementing automatic differentiation, candle and burn directly use RwLock or Arc smart pointers, avoiding ordinary lifetime-affected variables to represent tensors.</p>
<p>My view is that if we need to introduce automatic differentiation in the future, we need to do the following two things:</p>
<ul>
<li class="">write a separate AI frontend program that uses RSTSR as a backend, rather than writing a frontend directly in RSTSR;</li>
<li class="">seek cooperation with technology companies.</li>
</ul>
<p>Developing a self-made automatic differentiation program without connecting to industry needs is not necessarily meaningless, but it is difficult to win an audience; assuming Rust can indeed do machine learning, then in the end, projects led by technology companies will be more widely adopted than ours, so that we would waste too much time before our programs are abandoned. If our goal is only multi-backend scientific computing, then we have much more freedom in programming, and the program difficulty is greatly reduced; before large companies do this at scale, I am confident that we can do it well, at least without wasting time.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="32-abandoned-feature-overloading-assignment-statements">3.2. Abandoned Feature: Overloading Assignment Statements<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#32-abandoned-feature-overloading-assignment-statements" class="hash-link" aria-label="Direct link to 3.2. Abandoned Feature: Overloading Assignment Statements" title="Direct link to 3.2. Abandoned Feature: Overloading Assignment Statements" translate="no">​</a></h3>
<p>This is a Rust feature. In C++, the equals sign <code>=</code> can be overloaded with the <code>operator=</code> function; Rust does not allow this.</p>
<p>The result is that at least the following two convenient C++ practices are infeasible in Rust:</p>
<ul>
<li class="">
<p>regarding lazy evaluation, if we care about memory reuse, a typical example in C++'s Eigen library is</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">mat1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">noalias</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mat2 </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> mat2</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>This guarantees that <code>mat1</code>'s memory can be reused, but this is achieved through <code>operator=</code> overloading.</p>
</li>
<li class="">
<p>similar to MPQC's tensor contraction</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">tau</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"a,b,i,j"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">t2</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"a,b,i,j"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">t1</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"a,i"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">t1</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"b,j"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>the contraction operation needs the index-label information on both sides of <code>operator=</code>, and cannot be simply completed by assigning the RHS to the LHS.</p>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="33-rstsr-data-structures">3.3. RSTSR Data Structures<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#33-rstsr-data-structures" class="hash-link" aria-label="Direct link to 3.3. RSTSR Data Structures" title="Direct link to 3.3. RSTSR Data Structures" translate="no">​</a></h3>
<p>The RSTSR project has learned (or plans to learn) strategies from many other libraries:</p>
<ul>
<li class="">ndarray: data structures, lifetime management, vectorization of reduce operations;</li>
<li class="">candle + cudarc: GPU backend integration into Rust programs;</li>
<li class="">burn: the external API of multi-backend implementations;</li>
</ul>
<p>As the basic data structure, RSTSR's tensor will be expressed in the following way:</p>
<p><img decoding="async" loading="lazy" alt="RSTSR basic data structure" src="https://restgroup.github.io/rstsr-book/assets/images/rstsr-basic-structure-cf3eb2b909279473ef05f999a6bc8fd6.png" width="1831" height="701" class="img_ev3q"></p>
<ul>
<li class="">tensors are split into underlying data (<code>DataOwned</code>) and layout (<code>Layout</code>);</li>
<li class="">shapes (<code>Layout</code>) are split into dimension (<code>shape</code>), stride (<code>stride</code>), and offset (<code>offset</code>);</li>
<li class="">the dimension type is specified by <code>DimAPI</code>, which can be fixed-dimension arrays (<code>[usize; N]</code>) or variable-dimension arrays (<code>Vec&lt;usize&gt;</code>); efficient computation generally prefers the former.</li>
<li class="">underlying data is split into backend (<code>DeviceAPI</code>), underlying data type (<code>RawVec</code>), lifetime and ownership;</li>
<li class="">since the backend and the underlying data are somewhat coupled, the split strategy is shown in the figure above.</li>
</ul>
<p>The above data structure is quite different from both burn and ndarray:</p>
<ul>
<li class="">burn directly defines <code>Tensor&lt;B, D, T&gt;</code>, but it completely relies on RwLock for variable ownership and lifetimes; and burn only supports fixed dimensions;</li>
<li class="">our implementation strategy is closer to ndarray; but ndarray only implements on CPU, using a custom data type (equivalent to manually reimplementing <code>Vec&lt;T&gt;</code>, with a fair amount of unsafe code). In RSTSR's implementation, for the CPU backend, the simpler <code>Vec&lt;T&gt;</code> is used as the basic data storage format.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="34-on-the-implementation-of-views">3.4. On the Implementation of Views<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#34-on-the-implementation-of-views" class="hash-link" aria-label="Direct link to 3.4. On the Implementation of Views" title="Direct link to 3.4. On the Implementation of Views" translate="no">​</a></h3>
<p>High-dimensional tensors inevitably involve the concept of <a href="https://numpy.org/doc/stable/user/basics.copies.html" target="_blank" rel="noopener noreferrer" class="">view</a>. In our implementation, the <code>TensorBase</code> type is defined as</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token type-definition class-name">TensorBase</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">R</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">DimAPI</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">crate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">R</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Vec&lt;T&gt;/CudaSlice&lt;T&gt; (with lifetime and backend)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">crate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> layout</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Layout</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// {shape, stride, offset}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>The view (struct <code>DataRef</code>) is directly defined as</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">enum</span><span class="token plain"> </span><span class="token type-definition class-name">DataRef</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token lifetime-annotation symbol" style="color:#36acaa">'a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">S</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">TrueRef</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token lifetime-annotation symbol" style="color:#36acaa">'a</span><span class="token plain"> </span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">ManuallyDropOwned</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">ManuallyDrop</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">S</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">TensorView</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token lifetime-annotation symbol" style="color:#36acaa">'a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">B</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">TensorBase</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">DataRef</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token lifetime-annotation symbol" style="color:#36acaa">'a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Storage</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">B</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>and we generally only use <code>TrueRef</code>, which means our views are literally, in the literal sense, references to the <code>Storage&lt;T, B&gt;</code> type. <code>ManuallyDropOwned</code> is only used to initialize <code>TensorView&lt;T, Ix1&gt;</code> from <code>&amp;'a [T]</code>.</p>
<p>This differs considerably from ndarray; they store all the underlying information in <code>ArrayBase</code>:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token type-definition class-name">ArrayBase</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"> </span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">RawData</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    data</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Customized Vec&lt;T&gt; if OwnedRepr</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ptr</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">std</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">ptr</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">NonNull</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Elem</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// offset</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    dim</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">                          </span><span class="token comment" style="color:#999988;font-style:italic">// shape</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    strides</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">                      </span><span class="token comment" style="color:#999988;font-style:italic">// stride</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>But if this vector is referenced (<code>ViewRepr</code>), then <code>ArrayBase.data</code> only has a lifetime:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token type-definition class-name">ViewRepr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">A</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> life</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">PhantomData</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">A</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>We did not adopt ndarray's approach. This is because outside the CPU device, the purpose of a pointer can only be to access the underlying data and its associated backend device information, and should not be used for pointer arithmetic (for concrete tensor computations). This also requires that referenced data also carry the underlying data and its associated backend device information, and cannot be an empty lifetime.</p>
<p>Doing so naturally brings some trouble. The <code>ManuallyDropOwned</code> mentioned above is one of them. But this is much more convenient and intuitive for program maintenance.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="35-on-the-implementation-of-layout">3.5. On the Implementation of Layout<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#35-on-the-implementation-of-layout" class="hash-link" aria-label="Direct link to 3.5. On the Implementation of Layout" title="Direct link to 3.5. On the Implementation of Layout" translate="no">​</a></h3>
<p>Given the raw data, a tensor is defined by the dimension (<code>shape</code>), stride (<code>stride</code>), and offset (<code>offset</code>):</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token type-definition class-name">Layout</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">DimBaseAPI</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">crate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> shape</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">crate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> stride</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Stride</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">crate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> offset</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">usize</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    size</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">usize</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// this may not be necessary and may be removed</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>After clearly separating data from shape, many tensor operations can be explicitly performed only on the shape (layout), without touching the underlying data (data) at all. For example, if we implement a <code>transpose</code> function for <code>Layout&lt;D&gt;</code>, then transposing a tensor <code>TensorBase&lt;R, D&gt;</code> becomes very easy:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// different to actual implementation: `axes: &amp;[I: TryInto&lt;isize&gt; + Copy]`</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">transpose</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">I</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">R</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tensor</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">TensorBase</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">R</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> axes</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">isize</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">TensorBase</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">R</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"> </span><span class="token class-name">R</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">DataAPI</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">DimAPI</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> layout </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> tensor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">layout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">transpose</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">axes</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">unsafe</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token class-name">Ok</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">TensorBase</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new_unchecked</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tensor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> layout</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>While in ndarray, since the layout and the tensor are directly bound, the <code>permute_axes</code> function (equivalent to <code>transpose</code>) must be implemented directly on the tensor type (<a href="https://docs.rs/ndarray/latest/src/ndarray/impl_methods.rs.html#2391-2416" target="_blank" rel="noopener noreferrer" class="">source of <code>permute_axes</code></a>).</p>
<p>Operations that only change the Layout without concretely changing the tensor data include at least:</p>
<ul>
<li class="">taking sub-tensors, e.g., <code>a.slice([.., ..3, None, 5..8])</code>;</li>
<li class="">transposition, e.g., <code>a.transpose([0, 2, 1])</code>;</li>
<li class="">broadcasting (e.g., dimensions [5, 1, 3, 1] and [4, 3, 2] can be broadcast to [5, 4, 3, 2] without creating new tensor data);</li>
<li class="">iteration over tensors can be transformed into iteration over Layouts (exporting offset values), making iteration for any backend easy to implement.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="36-on-the-implementation-of-cpu-backend-tensor-addition">3.6. On the Implementation of CPU Backend Tensor Addition<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#36-on-the-implementation-of-cpu-backend-tensor-addition" class="hash-link" aria-label="Direct link to 3.6. On the Implementation of CPU Backend Tensor Addition" title="Direct link to 3.6. On the Implementation of CPU Backend Tensor Addition" translate="no">​</a></h3>
<p>As an example of separating the tensor library frontend from the backend, we take the addition operation to show the general idea of backend separation, as well as some simple performance optimization strategies.</p>
<p>First, we need to reach a consensus: we do not specially handle small matrix or tensor computations, especially in computational chemistry; therefore, we will assume that the computational cost of tensor operations far exceeds the computational cost of Layout transformations (generally no more than 10 μs).</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="361-function-signatures-of-addition-and-the-backend-separation-strategy">3.6.1. Function Signatures of Addition and the Backend Separation Strategy<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#361-function-signatures-of-addition-and-the-backend-separation-strategy" class="hash-link" aria-label="Direct link to 3.6.1. Function Signatures of Addition and the Backend Separation Strategy" title="Direct link to 3.6.1. Function Signatures of Addition and the Backend Separation Strategy" translate="no">​</a></h4>
<p>This part is not a distinctive feature of this library; it has already been implemented in ndarray.</p>
<p>We can notice that addition has several cases:</p>
<ol>
<li class=""><code>C = &amp;A + &amp;B</code></li>
<li class=""><code>C = A.view() + B.view()</code></li>
<li class=""><code>C =  A + &amp;B</code></li>
<li class=""><code>C =  A +  B</code></li>
<li class=""><code>C = &amp;A + b</code> (<code>b</code> as scalar)</li>
<li class=""><code>C =  A + b</code> (<code>b</code> as scalar)</li>
<li class=""><code>C += &amp;B</code></li>
<li class=""><code>C += b</code> (<code>b</code> as scalar)</li>
<li class="">......</li>
</ol>
<p>There are quite a few cases that can appear here, but in general, addition operations are divided into 6 cases:</p>
<ol>
<li class=""><code>add_tenary(&amp;mut C, &amp;A, &amp;B)</code>,</li>
<li class=""><code>add_binary(&amp;mut A, &amp;B); let C = A</code>,</li>
<li class=""><code>add_assign_binary(&amp;mut C, &amp;B)</code>,
cases 4–6 are when <code>B</code> is not a tensor but a scalar; we will not discuss these cases for now.</li>
</ol>
<p>Note that,</p>
<ul>
<li class=""><code>C = &amp;A + &amp;B</code> and <code>C = A.view() + B.view()</code> should be implemented as <code>add_tenary(&amp;mut C, &amp;A, &amp;B)</code>;</li>
<li class=""><code>C = A + &amp;B</code> and <code>C = A + B</code> should be implemented as <code>add_binary(&amp;mut A, &amp;B); let C = A</code>;<!-- -->
<ul>
<li class="">when allowed, it will inplace execute <code>A = &amp;A + &amp;B</code>, and then assign <code>C = A</code>;</li>
<li class="">but if the dimensions do not allow it (<code>B.shape()</code> not broadcastable to <code>A.shape()</code>), then execute <code>add_tenary(&amp;mut C, &amp;A, &amp;B)</code>;</li>
</ul>
</li>
<li class=""><code>C += &amp;B</code> is implemented as <code>add_assign_binary(&amp;mut C, &amp;B)</code>.<!-- -->
<ul>
<li class="">it should be noted that <code>add_binary(&amp;mut C, &amp;B)</code> and <code>add_assign_binary(&amp;mut C, &amp;B)</code> have very similar tasks, but the former is <code>C = &amp;C + &amp;B</code> while the latter is <code>C += &amp;B</code>; <code>+</code> (add) and <code>+=</code> (add-assign) are not the same operation. But similarly, both are binary operations with the same function type.</li>
</ul>
</li>
</ul>
<p>Finally, we summarize the ternary and binary operations as</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">op_mutc_refa_refb_func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    c</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> </span><span class="token class-name">TensorBase</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">RC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DC</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    a</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">TensorBase</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">RA</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DA</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    b</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">TensorBase</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">RB</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DB</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    f</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">F</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">op_muta_refb_func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    a</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> </span><span class="token class-name">TensorBase</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">RA</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DA</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    b</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">TensorBase</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">RB</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DB</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    f</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">F</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>and derive the following assignment binary operation</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">op_refa_refb_func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    a</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">TensorBase</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">RA</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DA</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    b</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">TensorBase</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">RB</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">DB</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    f</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">F</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Tensor</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">DA</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> </span><span class="token class-name">DimMaxAPI</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">DB</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Max</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">B</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>At this point, the tensor-level function abstraction is complete. The remaining tasks are:</p>
<ul>
<li class="">at the user-usage level, implement the <code>Add</code>, <code>AddAssign</code> traits upward;</li>
<li class="">for the backends, implement the concrete tensor addition operations downward.</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="362-function-signatures-of-the-addition-backend">3.6.2. Function Signatures of the Addition Backend<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#362-function-signatures-of-the-addition-backend" class="hash-link" aria-label="Direct link to 3.6.2. Function Signatures of the Addition Backend" title="Direct link to 3.6.2. Function Signatures of the Addition Backend" translate="no">​</a></h4>
<p>The concrete implementation of tensor addition requires at minimum the following data:</p>
<ul>
<li class="">the tensor's raw data (<code>Vec&lt;T&gt;</code> or <code>&amp;[T]</code> on CPU);</li>
<li class="">the tensor's shape information (<code>Layout&lt;D&gt;</code>)</li>
</ul>
<p>In the <code>storage/operators.rs</code> file, for the following cases, we defined operation interfaces:</p>
<ul>
<li class="">
<p><code>add_tenary(&amp;mut C, &amp;A, &amp;B)</code></p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">trait</span><span class="token plain"> </span><span class="token type-definition class-name">DeviceAddAPI</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TA</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">TB</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">TC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token constant" style="color:#36acaa">TA</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">core</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">ops</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">Add</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TB</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Output</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">TC</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token class-name">D</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">DimAPI</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">DeviceAPI</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TA</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token class-name">DeviceAPI</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TB</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token class-name">DeviceAPI</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TC</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">op_mutc_refa_refb_add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          c</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> </span><span class="token class-name">Storage</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          lc</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">Layout</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          a</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">Storage</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TA</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          la</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">Layout</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          b</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">Storage</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TB</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          lb</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">Layout</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><code>add_assign_binary(&amp;mut C, &amp;B)</code></p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">trait</span><span class="token plain"> </span><span class="token type-definition class-name">DeviceAddAssignAPI</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TA</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">TB</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token constant" style="color:#36acaa">TA</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">core</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">ops</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">AddAssign</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TB</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token class-name">D</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">DimAPI</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">DeviceAPI</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TA</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token class-name">DeviceAPI</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TB</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">op_muta_refb_add_assign</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          a</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> </span><span class="token class-name">Storage</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TA</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          la</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">Layout</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          b</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">Storage</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TB</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          lb</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">Layout</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><code>add_binary(&amp;mut A, &amp;B); let C = A</code>: the current implementation of this case is lazy; it is currently done in <code>DeviceOp_MutA_RefB_API</code>, without explicit backend separation.</p>
</li>
</ul>
<p>At this point, the frontend/backend separation is complete. For CPU, apply the above traits to <code>DeviceCPU</code>; for CUDA, apply the above traits to <code>DeviceCUDA</code>. CPU has been implemented, but CUDA still has a long way to go.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="363-cpu-tensor-addition-implementation">3.6.3. CPU Tensor Addition Implementation<a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#363-cpu-tensor-addition-implementation" class="hash-link" aria-label="Direct link to 3.6.3. CPU Tensor Addition Implementation" title="Direct link to 3.6.3. CPU Tensor Addition Implementation" translate="no">​</a></h4>
<p>Now we describe the CPU implementation of the above trait <code>DeviceAddAPI</code> (or function <code>op_mutc_refa_refb_add</code>). It is implemented in <code>cpu_backend/operators.rs</code>:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">impl</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">...</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token class-name">DeviceOp_MutC_RefA_RefB_API</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">...</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token class-name">CpuDevice</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">F</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">FnMut</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">TC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token constant" style="color:#36acaa">TA</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token constant" style="color:#36acaa">TB</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">op_mutc_refa_refb_func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        c</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> </span><span class="token class-name">Storage</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">CpuDevice</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lc</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">Layout</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        a</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">    </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token class-name">Storage</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TA</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">CpuDevice</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> la</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">Layout</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        b</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">    </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token class-name">Storage</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">TB</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">CpuDevice</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lb</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">Layout</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">D</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">F</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// such as `|c, a, b| *c = a.clone() +  b.clone()`</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// re-align layouts</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> layouts_full </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">translate_to_col_major</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">lc</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> la</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lb</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> layouts_full_ref </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> layouts_full</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">iter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">collect_vec</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">layouts_contig</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> size_contig</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">translate_to_col_major_with_contig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">layouts_full_ref</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// contiguous if possible, otherwise use iterator of layout</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> size_contig </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">CONTIG_SWITCH</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// CONTIG_SWITCH ~= 16</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> iter_c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">IterLayoutColMajor</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">layouts_contig</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> iter_a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">IterLayoutColMajor</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">layouts_contig</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> iter_b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">IterLayoutColMajor</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">layouts_contig</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">idx_c</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> idx_a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> idx_b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token macro property" style="color:#36acaa">izip!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">iter_c</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> iter_a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> iter_b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// compiler should optimize following for loop with SIMD</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">size_contig </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token function" style="color:#d73a49">f</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rawvec</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">idx_c </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                         </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rawvec</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">idx_a </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                         </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rawvec</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">idx_b </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// not contiguous after transpose in any cases</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> iter_c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">IterLayoutColMajor</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">layouts_full</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> iter_a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">IterLayoutColMajor</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">layouts_full</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> iter_b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">IterLayoutColMajor</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">layouts_full</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">idx_c</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> idx_a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> idx_b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token macro property" style="color:#36acaa">izip!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">iter_c</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> iter_a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> iter_b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token function" style="color:#d73a49">f</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rawvec</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">idx_c</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                     </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rawvec</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">idx_a</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                     </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rawvec</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">idx_b</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">Ok</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>This is a generic ternary operation implementation; implementing addition through this function is very easy:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">op_mutc_refa_refb_func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    c</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lc</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> la</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lb</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token closure-params">c</span><span class="token closure-params punctuation" style="color:#393A34">,</span><span class="token closure-params"> a</span><span class="token closure-params punctuation" style="color:#393A34">,</span><span class="token closure-params"> b</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">clone</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain">  b</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">clone</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>Let us briefly analyze the implementation principle of addition. The core part is how to rearrange the layouts of the three vectors. We first assume that the three vectors' layouts <code>lc, la, lb</code> have the same shape.</p>
<p>The core problem of elementwise tensor operations is memory alignment. Relative to the more complex Matrix Multiplication problem, on CPU, elementwise operations are very simple, and it is easy to achieve fairly high performance without complex tricks.</p>
<p>Imagine that there are now three kinds of layouts (assume tensors A, B, C all have the same layout):</p>
<ul>
<li class="">
<p>F-contiguous: this is the most convenient case; just scan the memory from head to tail.</p>
</li>
<li class="">
<p>C-contiguous: since our program only implements the F-contiguous iterator (but this is generally enough), we need to transpose it to F-contiguous:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">shape  : [  100, 200, 300] -&gt; [300, 200,   100]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">stride : [60000, 300,   1] -&gt; [  1, 300, 60000]</span><br></div></code></pre></div></div>
<p>In this way, the memory of all <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>100</mn><mo>×</mo><mn>200</mn><mo>×</mo><mn>300</mn></mrow><annotation encoding="application/x-tex">100 \times 200 \times 300</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">100</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">200</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">300</span></span></span></span> numbers is continuously aligned, and we just scan from head to tail.</p>
</li>
<li class="">
<p>Arbitrary strided with at least one dimension contiguous: this is a relatively special case, where the computation problem can be processed continuously, but is neither C-contiguous nor F-contiguous. Then we transpose the tensor by sorting the strides from small to large:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">shape  : [  100, 200, 300] -&gt; [200, 300,   100]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">stride : [80000,   1, 200] -&gt; [  1, 200, 80000]</span><br></div></code></pre></div></div>
<p>After sorting the strides from small to large, another problem arises: the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>100</mn><mo>×</mo><mn>200</mn><mo>×</mo><mn>300</mn></mrow><annotation encoding="application/x-tex">100 \times 200 \times 300</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">100</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">200</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">300</span></span></span></span> numbers are not contiguous: every <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>200</mn><mo>×</mo><mn>300</mn><mo>=</mo><mn>60000</mn></mrow><annotation encoding="application/x-tex">200 \times 300 = 60000</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em"></span><span class="mord">200</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">300</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">60000</span></span></span></span> numbers are contiguous, but after that, 20000 data elements must be skipped before reaching the next group of valid data. In this case, if the iterator is used directly, the compiler will not be hinted that the operations can be vectorized (SIMD) optimized. Therefore, we need to find a way to tell the program that this tensor actually has 60000 contiguous numbers; do contiguous computation on the contiguous numbers as much as possible, and jump over the non-contiguous places using the pointer positions given by the iterator.</p>
</li>
</ul>
<p>Finally, it should be noted that if the dimensions of the three tensors do not match, then the addition cannot be vectorized, and must be computed through the relatively inefficient iterator. The inefficiency here does not mean that iterators are bad, but that iterators cannot hint the compiler to vectorize at the <code>-O3</code> optimization level. For example, adding a C-contiguous matrix to an F-contiguous matrix is itself very unfriendly to memory contiguity. Even so, there are actually better approaches than simply using iterators (even if the contiguous memory cannot be vectorized, there is still a chance to fully exploit the L2 cache), but the implementation complexity would be too high, since we might also have to handle 3-dimensional tensors.</p>
<p>Of course, the current implementation is still fairly fast single-threaded; but this computation problem can also be completed with multithreading. I think we can implement simple, correct tensor addition in the main program (rstsr-core), and create a new parallel backend (<code>DeviceCPURayon</code>) in another library (e.g., rstsr-rayon), to perform parallel (or high-performance) tensor addition. The same is true for matrix multiplication. In addition, the above analysis may also be helpful for efficiently implementing multithreaded tensor addition.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="37-proposal-of-the-matrix-multiplication-symbol-">3.7. Proposal of the Matrix Multiplication Symbol <code>%</code><a href="https://restgroup.github.io/rstsr-book/blog/rstsr-first-report#37-proposal-of-the-matrix-multiplication-symbol-" class="hash-link" aria-label="Direct link to 37-proposal-of-the-matrix-multiplication-symbol-" title="Direct link to 37-proposal-of-the-matrix-multiplication-symbol-" translate="no">​</a></h3>
<p>I propose that in RSTSR, matrix multiplication (<code>matmul</code>) takes the <code>%</code> symbol. Its implementation has already been completed in <code>tensor/matmul.rs</code>. That is, the following expressions are matrix multiplication:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">a </span><span class="token operator" style="color:#393A34">%</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">%</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// in this way, `a` and `b` are consumed</span><br></div></code></pre></div></div>
<p>It will have similar functionality to the Python statement</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a @ b  </span><span class="token comment" style="color:#999988;font-style:italic"># c = np.matmul(a, b)</span><br></div></code></pre></div></div>
<p>The <code>%</code> symbol is the remainder operator (trait <code>Rem</code>).</p>
<p>Referring to Python's introduction of the <code>@</code> symbol as matrix multiplication in <a href="https://peps.python.org/pep-0465/" target="_blank" rel="noopener noreferrer" class="">PEP 465</a>, my considerations when introducing the <code>%</code> symbol into the RSTSR library are:</p>
<ul>
<li class="">replacing matrix multiplication with a binary operator is quite important for code readability; this is explained in detail in <a href="https://peps.python.org/pep-0465/" target="_blank" rel="noopener noreferrer" class="">PEP 465</a>;</li>
<li class="">the reason Rust cannot use the <code>@</code> symbol is that it is already a <a href="https://doc.rust-lang.org/book/appendix-02-operators.html" target="_blank" rel="noopener noreferrer" class="">pattern binding binary operator</a>; therefore, in the Rust language, it is in any case impossible to use <code>@</code> for matrix multiplication as Python does;</li>
<li class="">the <a href="https://doc.rust-lang.org/reference/expressions.html#expression-precedence" target="_blank" rel="noopener noreferrer" class="">operator precedence</a> of the <code>%</code> symbol in Rust is the same as <code>*</code> and <code>/</code>, i.e., multiplication and division; while in Python, <code>@</code> has the same <a href="https://docs.python.org/3/reference/expressions.html#operator-precedence" target="_blank" rel="noopener noreferrer" class="">operator precedence</a> as <code>*</code>, <code>/</code>, <code>//</code>, <code>%</code>;</li>
<li class="">although the <code>%</code> symbol is very common in integer remainder operations, the symbol is almost impossible to use in matrix operations;</li>
<li class="">disregarding mirror planes parallel to and perpendicular to the page, both the <code>%</code> symbol and the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>×</mo></mrow><annotation encoding="application/x-tex">\times</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em"></span><span class="mord">×</span></span></span></span> sign have <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>S</mi><mn>4</mn></msub></mrow><annotation encoding="application/x-tex">S_4</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0576em">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">4</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> symmetry (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mover accent="true"><mi>C</mi><mo>^</mo></mover><mn>2</mn></msub><mo>+</mo><mover accent="true"><mi>i</mi><mo>^</mo></mover></mrow><annotation encoding="application/x-tex">\hat{C}_2 + \hat{i}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0968em;vertical-align:-0.15em"></span><span class="mord"><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.9468em"><span style="top:-3em"><span class="pstrut" style="height:3em"></span><span class="mord mathnormal" style="margin-right:0.0715em">C</span></span><span style="top:-3.2523em"><span class="pstrut" style="height:3em"></span><span class="accent-body" style="left:-0.1667em"><span class="mord">^</span></span></span></span></span></span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.923em"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.923em"><span style="top:-3em"><span class="pstrut" style="height:3em"></span><span class="mord mathnormal">i</span></span><span style="top:-3.2285em"><span class="pstrut" style="height:3em"></span><span class="accent-body" style="left:-0.25em"><span class="mord">^</span></span></span></span></span></span></span></span></span></span>).</li>
</ul>]]></content>
        <author>
            <name>Andrew J. Zhu (祝震予)</name>
            <uri>https://github.com/ajz34</uri>
        </author>
    </entry>
</feed>