<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Publishing DTD v1.2 20120330//EN"
        "http://jats.nlm.nih.gov/publishing/1.2/JATS-journalpublishing1.dtd">
<!--<?xml-stylesheet type="text/xsl" href="article.xsl"?>-->
<article article-type="research-article" dtd-version="1.2" xml:lang="en" xmlns:mml="http://www.w3.org/1998/Math/MathML"
         xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <front>
        <journal-meta>
            <journal-id journal-id-type="issn">2303-9868</journal-id>
            <journal-id journal-id-type="eissn">2227-6017</journal-id>
            <journal-title-group>
                <journal-title>Международный научно-исследовательский журнал</journal-title>
            </journal-title-group>
            <issn pub-type="epub">2303-9868</issn>
            <publisher>
                <publisher-name>ООО Цифра</publisher-name>
            </publisher>
        </journal-meta>
        <article-meta>
            <article-id pub-id-type="doi">10.60797/IRJ.2024.143.115</article-id>
            <article-categories>
                <subj-group>
                    <subject>Brief communication</subject>
                </subj-group>
            </article-categories>
            <title-group>
                <article-title>РЕАЛИЗАЦИЯ МЕТОДА СОПРЯЖЕННЫХ ГРАДИЕНТОВ НА ГРАФИЧЕСКОМ ПРОЦЕССОРЕ С ПРИМЕНЕНИЕМ МАТРИЧНЫХ МЕТОДОВ РЕШЕНИЯ СЛАУ
                </article-title>
            </title-group>
            <contrib-group>
                <contrib contrib-type="author">
                    <contrib-id contrib-id-type="orcid">https://orcid.org/0000-0002-1863-2597</contrib-id>
                    <name>
                        <surname>Некрасов</surname>
                        <given-names>Кирилл Александрович</given-names>
                    </name>
                    <email>kirillnkr@mail.ru</email>
                    <xref ref-type="aff" rid="aff-1">1</xref>

                </contrib><contrib contrib-type="author" corresp="yes">
                    <contrib-id contrib-id-type="orcid">https://orcid.org/0000-0003-2192-1880</contrib-id>
                    <name>
                        <surname>Пицхелаури</surname>
                        <given-names>Сергей Сергеевич</given-names>
                    </name>
                    <email>lauri2011@mail.ru</email>
                    <xref ref-type="aff" rid="aff-2">2</xref>

                </contrib><contrib contrib-type="author">
                    
                    <name>
                        <surname>Устюжанин</surname>
                        <given-names>Данил Алексеевич</given-names>
                    </name>
                    <email>danil.ustiuzhanin@urfu.me</email>
                    
                </contrib>
            </contrib-group>
            <aff id="aff-1"><label>1</label>Уральский федеральный университет имени первого Президента России Б.Н. Ельцина</aff><aff id="aff-2"><label>2</label>Уральский Федеральный университет имени первого Президента России Б. Н. Ельцина</aff>
            
        <pub-date publication-format="electronic" date-type="pub" iso-8601-date="2024-05-31">
            <day>31</day>
            <month>05</month>
            <year>2024</year>
        </pub-date>
        
            
        <pub-date pub-type="collection">
            <year>2024</year>
        </pub-date>
        
            <volume>9</volume>
            <issue>143</issue>
            <fpage>1</fpage>
            <lpage>9</lpage>
            <history>
                
        <date date-type="received" iso-8601-date="2024-05-29">
            <day>29</day>
            <month>05</month>
            <year>2024</year>
        </date>
        
                
        <date date-type="accepted" iso-8601-date="2024-05-29">
            <day>29</day>
            <month>05</month>
            <year>2024</year>
        </date>
        
            </history>
            <permissions>
                <copyright-statement>Copyright: &#x00A9; 2022 The Author(s)</copyright-statement>
                <copyright-year>2022</copyright-year>
                <license license-type="open-access" xlink:href="http://creativecommons.org/licenses/by/4.0/">
                    <license-p>This is an open-access article distributed under the terms of the Creative Commons
                        Attribution 4.0 International License (CC-BY 4.0), which permits unrestricted use, distribution,
                        and reproduction in any medium, provided the original author and source are credited. See <uri
                                xlink:href="http://creativecommons.org/licenses/by/4.0/">
                            http://creativecommons.org/licenses/by/4.0/</uri>.
                    </license-p>
                </license>
            </permissions>
            <self-uri xlink:href="https://research-journal.org/archive/5-143-2024-may/10.60797/IRJ.2024.143.115"/>
            <abstract>
                <p>В работе представлен алгоритм решения систем линейных алгебраических уравнений (СЛАУ) методом сопряженных градиентов на графическом процессоре. В качестве основного инструмента реализации предложен класс-контейнер для работы с матрицами на базе технологии NVIDIA CUDA. Производительность решения СЛАУ методами Крамера и сопряженных градиентов была сопоставлена на центральном и графическом процессорах. Результаты исследования показали, что распараллеленный метод сопряженных градиентов, выполненный на графическом процессоре, обладает наибольшей эффективностью при обработке СЛАУ с симметричной положительно определенной основной матрицей. Рассматриваемый подход к параллельной обработке матричных операций имеет потенциал для применения в различных областях, где требуется решение крупных систем уравнений, таких как в науке, инженерии и финансах. В целом, данная работа представляет практическую значимость в области оптимизации производительности вычислений и закладывает фундамент для решения многих математических задач на графическом процессоре.</p>
            </abstract>
            <kwd-group>
                <kwd>распараллеливание алгоритмов</kwd>
<kwd> решение СЛАУ на графическом процессоре</kwd>
<kwd> матричные операции</kwd>
</kwd-group>
        </article-meta>
    </front>
    <body> 
        
 
        
<sec>
	<title>HTML-content</title>
	<p>1. Введение</p>
	<p>Системы линейных алгебраических уравнений (СЛАУ) являются фундаментом задач для многих областей естествознания, включая механику, электротехнику, экономику и компьютерную графику. Способы решения СЛАУ имеют важное значение, особенно при обработке большого количества уравнений. Методы решения СЛАУ делятся на точные и приближенные, включая итерационные методы. Алгоритмы для вычислительных машин, основанные на точных методах, таких как метод Гаусса и метод Крамера, подходят для систем порядка не выше 20, в то время как итерационные методы могут обрабатывать системы более высокого порядка.</p>
	<p>Одним из подходов к решению СЛАУ является параллельное програм­мирование, включая использование графических процессоров (GPU). В отличие от центрального процессора (CPU), GPU имеет сотни или тысячи ядер, способных обрабатывать вычисления одновременно. Это делает GPU более эффективным для параллельных задач, таких как обработка графики, научные вычисления и машинное обучение. Кроме того, на GPU реализуются различные методы решения СЛАУ.</p>
	<p>Метод сопряженных градиентов относится к итерационным методам и основывается на умножении матриц и вычислении скалярных произведений векторов. Умножение матриц строится на основе нахождения суммы произведений соответствующих элементов исходных матриц, т. е. состоит из множества несвязных вычислений. Поэтому метод сопряженных градиентов подходит для распараллеливания на графическом процессоре.</p>
	<p>2. Работа с матрицами при использовании
технологии CUDA</p>
	<p>Архитектура CUDA представляет собой специальный набор инструментов и библиотек, предназначенный для программирования графических процессоров. В качестве языков программирования CUDA поддерживает Python, C, C++ и т. д. Распараллеливание вычислений на GPU достигается за счет запуска большого количества потоков. Потоки в архитектуре CUDA представляются в виде сложной структуры. На верхнем уровне располагается сетка, которая является дискретным трехмерным пространством блоков, каждый блок в свою очередь трехмерным простран­ством потоков.</p>
	<p>Матрицы заданного размера, состоящие из действительных чисел, образуют следующее линейное пространство:</p>
	<code>[LATEX_FORMULA]M_{n \times m}=\left\{\left.\left(\begin{array}{ccc} a_{00} &amp;amp; \cdots &amp;amp; a_{0 m-1} \\ \vdots &amp;amp; \ddots &amp;amp; \vdots \\ a_{n-10} &amp;amp; \cdots &amp;amp; a_{n-1 m-1} \end{array}\right) \right\rvert\, a_{i j} \in \mathbb{R}\right\}[/LATEX_FORMULA]</code>
	<p>В настоящей работе матрицы представляли как одномерные динамичес­кие массивы. Доступ к элементу матрицы  осуществляли по следующему соотношению: [LATEX_FORMULA]p t r+i * M+j, i=\overline{0, N-1}, j=\overline{0, M-1})[/LATEX_FORMULA], где N – число строк в матрице, M – число столбцов в матрице, ptr – указатель на первый элемент массива. В качестве «обертки» для динамического массива использовали класс-контейнер devMatrix.</p>
	<fig id="F1">
		<label>Figure 1</label>
		<caption>
			<p>Основные методы класса devMatrix</p>
		</caption>
		<alt-text>Основные методы класса devMatrix</alt-text>
		<graphic xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/media/images/2024-05-29/030afa46-7506-40c0-a150-894a54877059.png"/>
	</fig>
	<p>Класс devMatrix включает все стандартные специальные методы (см. таб. 1), в том числе перемещающий конструктор и оператор присваивания. Класс Matrix является прообразом класса devMatrix и предназначен для работы с матрицами на CPU. Для удобства devMatrix имеет конструктор от Matrix.</p>
	<p>3. Сложение матриц на GPU</p>
	<p>В качестве иллюстрации внутреннего устройства класса devMatrix и работы CUDA, рассмотрим перегрузку оператора «+». Данный оператор осуществляет сложение двух матриц. Под сложением матриц будем понимать следующую операцию:</p>
	<code>[LATEX_FORMULA]\begin{gathered} A_{n m}+B_{n m}=\left(\begin{array}{ccc} a_{00} &amp;amp; \cdots &amp;amp; a_{0 m-1} \\ \vdots &amp;amp; \ddots &amp;amp; \vdots \\ a_{n-10} &amp;amp; \cdots &amp;amp; a_{n-1 m-1} \end{array}\right)+\left(\begin{array}{ccc} b_{00} &amp;amp; \cdots &amp;amp; b_{0 m-1} \\ \vdots &amp;amp; \ddots &amp;amp; \vdots \\ b_{n-10} &amp;amp; \cdots &amp;amp; b_{n-1 m-1} \end{array}\right)= \\ \left(\begin{array}{ccc} a_{00}+b_{00} &amp;amp; \cdots &amp;amp; a_{0 m-1}+b_{0 m-1} \\ \vdots &amp;amp; \ddots &amp;amp; \vdots \\ a_{n-10}+b_{n-10} &amp;amp; \cdots &amp;amp; a_{n-1 m-1}+b_{n-1 m-1} \end{array}\right) . \end{gathered}[/LATEX_FORMULA]</code>
	<p>При использовании CUDA, сумма каждой пары элементов (aij, bij) вычисляется в отдельном потоке. В данном случае использовали двумерное представление сетки и блока, при этом число блоков в одном из измерений вычисляли как ближайшее целое, большее или равное числу [LATEX_FORMULA]\frac{N}{32}\left(\frac{M}{32}\right)[/LATEX_FORMULA]. Блоки имели размер 32 × 32 потока. Каждый поток обрабатывал одну сумму (см. рис. 1).</p>
	<fig id="F2">
		<label>Figure 2</label>
		<caption>
			<p>Блок-схема суммы матриц</p>
		</caption>
		<alt-text>Блок-схема суммы матриц</alt-text>
		<graphic xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/media/images/2024-05-28/44464fe5-6334-4b1b-8308-dd62041c9165.png"/>
	</fig>
	<fig id="F3">
		<label>Figure 3</label>
		<caption>
			<p>Сравнение производительности сложения матриц на CPU и GPU</p>
		</caption>
		<alt-text>Сравнение производительности сложения матриц на CPU и GPU</alt-text>
		<graphic xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/media/images/2024-05-28/6da2aa30-99bf-493c-b89d-46de8235bf9d.png"/>
	</fig>
	<p>Распараллеливание на GPU, при больших размерностях матриц, значительно сокращает время обработки операции сложения (см. рис. 2). При этом стоит отметить, что возрастание времени не связано на прямую с процессом суммирования элементов на GPU. Возрастание времени в данном случае определяется тем, что процесс выделения непрерывного участка памяти требует дополнительных вычислений. Также в данном случае размерность матрицы сильно ограничена объемом глобальной памяти, например квадратная матрица порядка 25000, состоящая из объектов типа double, занимает:</p>
	<code>[LATEX_FORMULA]\frac{25000^2 \cdot 8}{1024^3} \approx 4.66 \text { ГБ }[/LATEX_FORMULA]</code>
	<p>Для корректной работы, стоит учитывать, что в какой-то момент времени будет как минимум два объекта типа devMatrix, при условии, что поддерживается перемещающий конструктор. Идеология перемещающих конструктора и оператора играют важную роль в ОПП реализации матричных операций. При манипуляции большими объемами данных стоит избегать их дублирования, которое возникает при инициализации или переопределении в результате возвращения из функции rvalue объектов. В противном случае минимальное количество объектов при обработке операции возрастает до трех, что соответствует (в случае квадратной матрицы порядка 25000) 13.98 ГБ. Если отбросить ограничения, связанные с памятью, на современных видеокартах на размерность сетки накладывается ограничение в максимальное число блоков, что соответствует максимальной размерности первого измерения. Максимальная размерность блока составляет 1024 потока (подробные данные см. гайд ссылка на гайд).</p>
	<p>Таким образом максимальное количество строк/столбцов в квадратной матрице определяется следующим образом:</p>
	<p>с учетом что в нашей реализации [LATEX_FORMULA]\frac{N}{32}[/LATEX_FORMULA] должно быть кратно [LATEX_FORMULA]\text { 32: } N=1482880 \text {, }[/LATEX_FORMULA] что во много раз превышает лимит памяти.</p>
	<p>В результате верхнюю границу размеров матрицы определяет именно объем глобальной память GPU.</p>
	<p>4. Умножение матриц на GPU</p>
	<p>Умножение матриц в алгебраической форме записывается следующим образом:</p>
	<code>[LATEX_FORMULA]A_{n \times m} \cdot B_{m \times k}=C_{n \times k}, \quad c_{i j}=\sum_{d=0}^{m-1} a_{i d} \cdot b_{d j}[/LATEX_FORMULA]</code>
	<p>Классический распараллеленный алгоритм произведения матрицы схож с суммированием, но для каждого элемента отдельно запускается цикл, в котором рассчитывается сумма произведений (см. рис. 3). Важно, чтобы промежуточные значения суммы хранились в быстрой регистровой памяти GPU, иначе произойдет падение производительности программы.</p>
	<fig id="F4">
		<label>Figure 4</label>
		<caption>
			<p>Блок-схема произведения матриц</p>
		</caption>
		<alt-text>Блок-схема произведения матриц</alt-text>
		<graphic xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/media/images/2024-05-28/a31e69ec-9b07-4ef7-b8a7-ade8acbafbfb.jpg"/>
	</fig>
	<fig id="F5">
		<label>Figure 5</label>
		<caption>
			<p>Сравнение производительности умножения матриц на CPU и GPU</p>
		</caption>
		<alt-text>Сравнение производительности умножения матриц на CPU и GPU</alt-text>
		<graphic xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/media/images/2024-05-28/65796e22-46dd-4bf9-87ec-cd96c5c2d888.jpg"/>
	</fig>
	<p>На данную реализацию произведения матриц накладываются те же ограничения, что на суммирование. Разница во времени между перемножением на CPU и GPU, значительно превосходит разницу в случае суммы (см. рис. 4).</p>
	<p>Представленный алгоритм является самой простой реализацией параллельного произведения. Существуют альтернативные алгоритмы:</p>
	<p>1. Распараллеливание не только вычисления отдельного элемента результирующей матрицы, но и отдельных произведений соответствующей суммы, за счет третьего измерения z в сетке. У данного алгоритма есть две глобальные проблемы. Первая заключается в гонке потоков на запись произведений, появляется она из-за того, что мы вынуждены обращаться не к регистровой памяти, а к глобальной. Причем в подобной реализации в сочетание с нашим представлением класса devMatrix за суммирование произведений одного элемента не всегда отвечает одни блок, поэтому накладывается ограничение на использование разделяемой памяти. Вторая проблема связана с резким уменьшением максимальной размерности матриц из-за уменьшения числа блоков в x, y измерении из-за добавления z измерения:</p>
	<p>2. Рассматривать сетку в двух измерениях соответствуя элементам результирующей матрицы. В каждом блоке будет происходить распараллеленное вычисление суммы произведений с использованием разделяемой памяти. Данный алгоритм позволит вычислять произведения матриц с самой высокой скоростью, но если будет происходить перемножение матриц [LATEX_FORMULA]A_{n \times m} \cdot B_{m \times k}[/LATEX_FORMULA], то максимальное значение k (число столбцов матрицы A, число строк матрицы B) равно 1024, из-за ограничения на число потоков внутри блока.</p>
	<p>По сравнению с указанными альтернативами, классический (простой) алгоритм предпочтителен, он обеспечивает хорошую скорость около граничной области размерности матриц по памяти.</p>
	<p>5. Метод сопряженных градиентов</p>
	<p>Пусть система из n линейных алгебраических уравнений c n неизвестными представлена в матричной форме: [LATEX_FORMULA]A \cdot X=B \text {, }[/LATEX_FORMULA]</p>
	<p>где </p>
	<p>– основная матрица системы,</p>
	<p>– столбец неизвестных, [LATEX_FORMULA]B=\left(\begin{array}{c} b_1 \\ b_2 \\ \ldots \\ b_n \end{array}\right)[/LATEX_FORMULA] – столбец свободных членов.</p>
	<p> </p>
	<p>Метод сопряженных градиентов, подразумевает, что основная матрица системы A – симметрична и положительно определена, т. е. [LATEX_FORMULA]\forall x \neq \theta \in \mathcal{R}^n:(A \cdot x, x)&amp;gt;0[/LATEX_FORMULA].</p>
	<p>Для решения такой системы методом сопряженных градиентов можно использовать следующее рекуррентное соотношение:</p>
	<p>Шаг 0:</p>
	<code>[LATEX_FORMULA]r_0=A \cdot X_0-B, \beta_0=\frac{\left(r_0, r_0\right)}{\left(A \cdot r_0, r_0\right)}, \Delta X_1=\beta_0 \cdot r_0, \alpha_0=0[/LATEX_FORMULA]</code>
	<p>[LATEX_FORMULA]X_0=\left(\begin{array}{c} \tilde{x}_1 \\ \tilde{x}_2 \\ \ldots \\ \tilde{x}_n \end{array}\right)[/LATEX_FORMULA] – произвольный вектор.</p>
	<p>Шаг индукции [LATEX_FORMULA]i(i=\overline{1, n-1})[/LATEX_FORMULA]</p>
	<code>[LATEX_FORMULA]X_i=X_i+\Delta X_i, \text { где } \Delta X_i=\alpha_{i-1} \cdot \Delta X_{i-1}+\beta_{i-1} \cdot r_{i-1}(i \neq 1)[/LATEX_FORMULA]</code>
	<code>[LATEX_FORMULA]r_i=A \cdot X_i-B,[/LATEX_FORMULA]</code>
	<code>[LATEX_FORMULA]\alpha_i=\frac{\left(r_i, r_i\right) \cdot\left(A \cdot r_i, \Delta X_i\right)-\left(r_i, \Delta X_i\right) \cdot\left(A \cdot r_i, r_i\right)}{\left(A \cdot \Delta X_i, \Delta X_i\right) \cdot\left(A \cdot r_i, r_i\right)-\left(A \cdot r_i, \Delta X_i\right)^2}[/LATEX_FORMULA]</code>
	<code>[LATEX_FORMULA]\beta_i=\frac{\left(r_i, \Delta X_i\right) \cdot\left(A \cdot r_i, \Delta X_i\right)-\left(r_i, r_i\right) \cdot\left(A \cdot \Delta X_i, \Delta X_i\right)}{\left(A \cdot \Delta X_i, \Delta X_i\right) \cdot\left(A \cdot r_i, r_i\right)-\left(A \cdot r_i, \Delta X_i\right)^2},[/LATEX_FORMULA]</code>
	<p>Отметим, что метод сопряженных градиентов всегда сходится к решению исходной СЛАУ за [LATEX_FORMULA]k \leq n[/LATEX_FORMULA]  итераций ([LATEX_FORMULA]n[/LATEX_FORMULA] – порядок системы).</p>
	<fig id="F6">
		<label>Figure 6</label>
		<caption>
			<p>Вид итогового алгоритма с учетом построенных инструментов для работы с матрицами</p>
		</caption>
		<alt-text>Вид итогового алгоритма с учетом построенных инструментов для работы с матрицами</alt-text>
		<graphic xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/media/images/2024-05-29/9c3b1756-45a1-40bb-8285-29924ffcfe79.png"/>
	</fig>
	<p>Расчет коэффициентов [LATEX_FORMULA]\alpha, \beta[/LATEX_FORMULA] происходит в специальной функции, которая распараллеливает скалярное произведение. Ядро реализовали с использованием редукции (см. рис. 6). Разбиение скалярных произведений происходит за счет добавления измерения y с индексацией [LATEX_FORMULA]i=\overline{0,5} \text {. }[/LATEX_FORMULA]</p>
	<fig id="F7">
		<label>Figure 7</label>
		<caption>
			<p>Блок-схема реализации скалярного произведения</p>
		</caption>
		<alt-text>Блок-схема реализации скалярного произведения</alt-text>
		<graphic xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/media/images/2024-05-29/bddce017-e48b-4ed7-a91c-8bf1bc53c737.png"/>
	</fig>
	<fig id="F8">
		<label>Figure 8</label>
		<caption>
			<p>Метод Крамера, спряжённых градиентов на CPU и GPU</p>
		</caption>
		<alt-text>Метод Крамера, спряжённых градиентов на CPU и GPU</alt-text>
		<graphic xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/media/images/2024-05-29/7d5a23ac-da32-4d9a-bb39-db63fd5673fd.jpg"/>
	</fig>
	<fig id="F9">
		<label>Figure 9</label>
		<caption>
			<p>Метод спряжённых градиентов на GPU</p>
		</caption>
		<alt-text>Метод спряжённых градиентов на GPU</alt-text>
		<graphic xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/media/images/2024-05-29/e7816617-855d-4106-8057-4d9073f2185e.jpg"/>
	</fig>
	<p>Итоговое сравнение производительности различных методов решения СЛАУ, показывает, что распараллеливание на GPU сильно уменьшает время (см. рис. 7, см рис. 8).</p>
	<p>Все тесты проводились на следующей конфигурации:</p>
	<p>Процессор: AMD Ryzen 5 5600 6-Core Processor 3.50 GHz;</p>
	<p>Оперативная память: 16,0 ГБ;</p>
	<p>Графический процессор: GeForce RTX 3060 12,0 ГБ, 3584 ядер CUDA.</p>
	<p>6. Заключение</p>
	<p>В настоящей работе предложены основные инструменты для обработки матричных операций с использованием технологии CUDA. На примере сложения и умножения матриц показано, что алгоритмы, построенные на распараллеливании вычислений, работают на несколько порядков эффективнее аналогичных последовательных программ на CPU. Определены границы размерностей матриц, которые можно обработать на GPU.</p>
	<p>На основе библиотеки devMatrix, построен алгоритм решения СЛАУ методом сопряженных градиентов, который превзошел аналогичный алгоритм на CPU и метод Крамера по скорости решения. Полученный результат демонстрирует актуальность технологии CUDA в контексте научных расчетов, а также предоставляет возможность написания простых, но в то же время эффективных матричных алгоритмов на базе библиотеки devMatrix.</p>
</sec>
        <sec sec-type="supplementary-material">
            <title>Additional File</title>
            <p>The additional file for this article can be found as follows:</p>
            <supplementary-material id="S1" xmlns:xlink="http://www.w3.org/1999/xlink"
                                    xlink:href="https://doi.org/10.5334/cpsy.78.s1">
                <!--[<inline-supplementary-material xlink:title="local_file" xlink:href="https://research-journal.org/media/articles/13546.docx">13546.docx</inline-supplementary-material>]-->
                <!--[<inline-supplementary-material xlink:title="local_file" xlink:href="https://research-journal.org/media/articles/13546.pdf">13546.pdf</inline-supplementary-material>]-->
                <label>Online Supplementary Material</label>
                <caption>
                    <p>Further description of analytic pipeline and patient demographic information. DOI:
                        <italic>
                            <uri>https://doi.org/10.60797/IRJ.2024.143.115</uri>
                        </italic>
                    </p>
                </caption>
            </supplementary-material>
        </sec>
    </body>
    <back>
        <ack>
            <title>Acknowledgements</title>
            <p>None</p>
        </ack>
        <sec>
            <title>Competing Interests</title>
            <p>None</p>
        </sec>
        <ref-list>
            <ref id="B1">
                    <label>1</label>
                    <mixed-citation publication-type="confproc">
                        Крылов В. И. Вычислительные методы в 2 т. / В. И. Крылов, В. В. Бобков, П. И. Монастырный. — Москва : Наука, 1976.
                    </mixed-citation>
                </ref><ref id="B2">
                    <label>2</label>
                    <mixed-citation publication-type="confproc">
                        Некрасов К. А. Параллельные вычисления общего назначения на графических процессорах / К. А. Некрасов, С. И. Поташников, А. С. Боярченков [и др.]. — Изд-во Уральского ун-та, 2016. — 103 с. — ISBN 978-5-7996-1722-6.
                    </mixed-citation>
                </ref><ref id="B3">
                    <label>3</label>
                    <mixed-citation publication-type="confproc">
                        Тумаков Д. Н. Технология программирования CUDA / Д. Н. Тумаков, Д. Е. Чикрин, А. А. Егорчев [и др.]. — Казань : Казанский федеральный ун-т. — ISBN 978-5-00019-913-8.
                    </mixed-citation>
                </ref><ref id="B4">
                    <label>4</label>
                    <mixed-citation publication-type="confproc">
                        Локтионов И. К. Численные методы / И. К. Локтионов. — Москва : Инфа-Инженерия, 2022. — 308 с. — ISBN 978-5-9729-0786-1.

                    </mixed-citation>
                </ref><ref id="B5">
                    <label>5</label>
                    <mixed-citation publication-type="confproc">
                        Огородникова О. М. Вычислительные методы в компьютерном инжиниринге / О. М. Огородникова. — Изд-во Уральского ун-та, 2013. — 130 с. — ISBN 978-5-7996-0816-3.
                    </mixed-citation>
                </ref><ref id="B6">
                    <label>6</label>
                    <mixed-citation publication-type="confproc">
                        Амосов А. А. Вычислительные методы для инженеров / А. А. Амосов, Ю. А. Дубинский, Н. В. Копченова. — Москва : Высш. шк, 1994. — 543 с. — ISBN 5-06-000625-5.
                    </mixed-citation>
                </ref><ref id="B7">
                    <label>7</label>
                    <mixed-citation publication-type="confproc">
                        Пирумов У. Г. Численные методы / У. Г. Пирумов, В. Ю. Гидаспов, И. Э. Иванов [и др.]. — Москва : Юрайт, 2023. — 421 с. — ISBN 978-5-534-03141-6.
                    </mixed-citation>
                </ref><ref id="B8">
                    <label>8</label>
                    <mixed-citation publication-type="confproc">
                        Снытиков А. В. Математическое моделирование и программная модель CUDA / А. В. Снытников, А. С. Колганов, Н. Н. Попова. — Москва : МАКС Пресс, 2018. — 171 с. — ISBN 978-5-317-05911-8.
                    </mixed-citation>
                </ref><ref id="B9">
                    <label>9</label>
                    <mixed-citation publication-type="confproc">
                        Тоуманен Б. Программирование GPU при помощи Python и CUDA / Б. Тоуманен. — Москва : ДМК Пресс, 2020. — 235 с. — ISBN 978-5-97060-821-0.
                    </mixed-citation>
                </ref><ref id="B10">
                    <label>10</label>
                    <mixed-citation publication-type="confproc">
                        Programming Guide // CUDA Toolkit Documentation. — URL: https://docs.nvidia.com/cuda/archive/11.4.0/cuda-c-programming-guide/index.html (accessed: 24.11.2023).

                    </mixed-citation>
                </ref>
        </ref-list>
    </back>
    <fundings>
        
                <funding lang="RUS">Работа выполнена на основе гранта Министерства образования РФ № FEUZ-2023-0013.</funding>
                
                <funding lang="ENG">The work was carried out on the basis of a grant from the Ministry of Education of the Russian Federation No. FEUZ-2023-0013.</funding>
                
    </fundings>
</article>