2023-09-30

This commit is contained in:
Gennadiy 2023-12-17 08:49:19 +03:00
parent ed71e6823d
commit 6f960bda29
8 changed files with 30 additions and 30 deletions

View file

@ -7,9 +7,9 @@ url: "https://pomodoro3.mircloud.ru"
# подпапка этой сборки для относительных URLs # подпапка этой сборки для относительных URLs
baseurl: "/color" baseurl: "/color"
# ссылка в верхнем левом углу заглавных страниц # ссылка в верхнем левом углу заглавных страниц
homepage_url: "https://gitea.com/pomodoro/3" homepage_url: "https://git.org.ru/pomodoro/3"
# представление ссылки # представление ссылки
homepage_name: "GITEA" homepage_name: "GIT.ORG.RU"
# подпапка альтернативной сборки # подпапка альтернативной сборки
older_tomato_baseurl: "" older_tomato_baseurl: ""
# часовой пояс для формата даты ISO-8601 # часовой пояс для формата даты ISO-8601

View file

@ -7,9 +7,9 @@ url: "https://pomodoro3.mircloud.ru"
# подпапка этой сборки для относительных URLs # подпапка этой сборки для относительных URLs
baseurl: "" baseurl: ""
# ссылка в верхнем левом углу заглавных страниц # ссылка в верхнем левом углу заглавных страниц
homepage_url: "https://gitea.com/pomodoro/3" homepage_url: "https://git.org.ru/pomodoro/3"
# представление ссылки # представление ссылки
homepage_name: "GITEA" homepage_name: "GIT.ORG.RU"
# подпапка альтернативной сборки # подпапка альтернативной сборки
color_tomato_baseurl: "/color" color_tomato_baseurl: "/color"
# часовой пояс для формата даты ISO-8601 # часовой пояс для формата даты ISO-8601

View file

@ -24,7 +24,7 @@ and depends on the execution environment.
*Further optimization: [Matrix multiplication in parallel streams]({{ '/en/2022/02/09/matrix-multiplication-parallel-streams.html' | relative_url }}).* *Further optimization: [Matrix multiplication in parallel streams]({{ '/en/2022/02/09/matrix-multiplication-parallel-streams.html' | relative_url }}).*
## Row-wise algorithm {#row-wise-algorithm} {% include heading.html text="Row-wise algorithm" hash="row-wise-algorithm" %}
The outer loop bypasses the rows of the first matrix `L`, then there is a loop across the *common side* The outer loop bypasses the rows of the first matrix `L`, then there is a loop across the *common side*
of the two matrices `M` and it is followed by a loop across the columns of the second matrix `N`. of the two matrices `M` and it is followed by a loop across the columns of the second matrix `N`.
@ -57,7 +57,7 @@ public static int[][] matrixMultiplicationLMN(int l, int m, int n, int[][] a, in
} }
``` ```
## Layer-wise algorithm {#layer-wise-algorithm} {% include heading.html text="Layer-wise algorithm" hash="layer-wise-algorithm" %}
The outer loop bypasses the *common side* of the two matrices `M`, then there is a loop across the rows The outer loop bypasses the *common side* of the two matrices `M`, then there is a loop across the rows
of the first matrix `L`, and it is followed by a loop across the columns of the second matrix `N`. of the first matrix `L`, and it is followed by a loop across the columns of the second matrix `N`.
@ -90,7 +90,7 @@ public static int[][] matrixMultiplicationMLN(int l, int m, int n, int[][] a, in
} }
``` ```
### Other algorithms {#other-algorithms} {% include heading.html text="Other algorithms" hash="other-algorithms" type="3" %}
The bypass of the columns of the second matrix `N` occurs before the bypass of the *common side* of the The bypass of the columns of the second matrix `N` occurs before the bypass of the *common side* of the
two matrices `M` and/or before the bypass of the rows of the first matrix `L`. two matrices `M` and/or before the bypass of the rows of the first matrix `L`.
@ -139,7 +139,7 @@ public static int[][] matrixMultiplicationNML(int l, int m, int n, int[][] a, in
{% endcapture %} {% endcapture %}
{%- include collapsed_block.html summary="Code without comments" content=collapsed_md -%} {%- include collapsed_block.html summary="Code without comments" content=collapsed_md -%}
## Comparing algorithms {#comparing-algorithms} {% include heading.html text="Comparing algorithms" hash="comparing-algorithms" %}
To check, we take two matrices `A=[500×700]` and `B=[700×450]`, filled with random numbers. First, we To check, we take two matrices `A=[500×700]` and `B=[700×450]`, filled with random numbers. First, we
compare the correctness of the implementation of the algorithms all results obtained must match. compare the correctness of the implementation of the algorithms all results obtained must match.

View file

@ -20,7 +20,7 @@ be reduced by more than two times. To check, let's take two rectangular matrices
*Further optimization: [Winograd Strassen algorithm]({{ '/en/2022/02/11/winograd-strassen-algorithm.html' | relative_url }}).* *Further optimization: [Winograd Strassen algorithm]({{ '/en/2022/02/11/winograd-strassen-algorithm.html' | relative_url }}).*
## Parallel stream {#parallel-stream} {% include heading.html text="Parallel stream" hash="parallel-stream" %}
We bypass the rows of the first matrix `L` in parallel mode. In each thread there are two nested loops: We bypass the rows of the first matrix `L` in parallel mode. In each thread there are two nested loops:
across the *common side* of two matrices `M` and across the columns of the second matrix `N`. Processing across the *common side* of two matrices `M` and across the columns of the second matrix `N`. Processing
@ -54,7 +54,7 @@ public static int[][] parallelMatrixMultiplication(int l, int m, int n, int[][]
} }
``` ```
## Three nested loops {#three-nested-loops} {% include heading.html text="Three nested loops" hash="three-nested-loops" %}
We take the *optimized* variant of algorithm, that uses cache of the execution environment better We take the *optimized* variant of algorithm, that uses cache of the execution environment better
than others. The outer loop bypasses the rows of the first matrix `L`, then there is a loop across than others. The outer loop bypasses the rows of the first matrix `L`, then there is a loop across
@ -88,7 +88,7 @@ public static int[][] sequentialMatrixMultiplication(int l, int m, int n, int[][
} }
``` ```
## Testing {#testing} {% include heading.html text="Testing" hash="testing" %}
To check, we take two matrices `A=[900×1000]` and `B=[1000×750]`, filled with random numbers. To check, we take two matrices `A=[900×1000]` and `B=[1000×750]`, filled with random numbers.
First, we compare the correctness of the implementation of the two algorithms matrix products First, we compare the correctness of the implementation of the two algorithms matrix products
@ -156,7 +156,7 @@ Stream | 113 | 144 | 117 | 114 | 114 | 117 | 120 | 125 | 111 | 113 || 118
Loops | 1357 | 530 | 551 | 569 | 535 | 538 | 525 | 517 | 518 | 514 || 615 Loops | 1357 | 530 | 551 | 569 | 535 | 538 | 525 | 517 | 518 | 514 || 615
``` ```
## Comparing algorithms {#comparing-algorithms} {% include heading.html text="Comparing algorithms" hash="comparing-algorithms" %}
On an eight-core Linux x64 computer, we create a Windows x64 virtual machine for tests. All On an eight-core Linux x64 computer, we create a Windows x64 virtual machine for tests. All
other things being equal, in the settings, we change the number of processors. We run the other things being equal, in the settings, we change the number of processors. We run the

View file

@ -26,7 +26,7 @@ environment. Let's compare the operating time of two algorithms.
*Algorithm using three nested loops: [Optimizing matrix multiplication]({{ '/en/2021/12/10/optimizing-matrix-multiplication.html' | relative_url }}).* *Algorithm using three nested loops: [Optimizing matrix multiplication]({{ '/en/2021/12/10/optimizing-matrix-multiplication.html' | relative_url }}).*
## Algorithm description {#algorithm-description} {% include heading.html text="Algorithm description" hash="algorithm-description" %}
Matrices must be the same size. We partition each matrix into 4 equally sized blocks. The blocks Matrices must be the same size. We partition each matrix into 4 equally sized blocks. The blocks
must be square, therefore if this is not the case, then first we supplement the matrices with zero must be square, therefore if this is not the case, then first we supplement the matrices with zero
@ -56,7 +56,7 @@ Blocks of the resulting matrix.
{% include image_svg.html src="/img/sums3.svg" style="width:240pt; height:33pt;" {% include image_svg.html src="/img/sums3.svg" style="width:240pt; height:33pt;"
alt="{\displaystyle{\begin{pmatrix}C_{11}&C_{12}\\C_{21}&C_{22}\end{pmatrix}}={\begin{pmatrix}P_{2}+P_{3}&T_{1}+P_{5}+P_{6}\\T_{2}-P_{7}&T_{2}+P_{5}\end{pmatrix}}.}" %} alt="{\displaystyle{\begin{pmatrix}C_{11}&C_{12}\\C_{21}&C_{22}\end{pmatrix}}={\begin{pmatrix}P_{2}+P_{3}&T_{1}+P_{5}+P_{6}\\T_{2}-P_{7}&T_{2}+P_{5}\end{pmatrix}}.}" %}
## Hybrid algorithm {#hybrid-algorithm} {% include heading.html text="Hybrid algorithm" hash="hybrid-algorithm" %}
We partition each matrix `A` and `B` into 4 equally sized blocks and, if necessary, we supplement We partition each matrix `A` and `B` into 4 equally sized blocks and, if necessary, we supplement
the missing parts with zeros. Perform 15 summations and 7 multiplications over the blocks we get the missing parts with zeros. Perform 15 summations and 7 multiplications over the blocks we get
@ -169,7 +169,7 @@ private static int[][] putQuadrants(int m, int n,
{% endcapture %} {% endcapture %}
{%- include collapsed_block.html summary="Helper methods" content=collapsed_md -%} {%- include collapsed_block.html summary="Helper methods" content=collapsed_md -%}
## Nested loops {#nested-loops} {% include heading.html text="Nested loops" hash="nested-loops" %}
To supplement the previous algorithm and to compare with it, we take the *optimized* variant of nested To supplement the previous algorithm and to compare with it, we take the *optimized* variant of nested
loops, that uses cache of the execution environment better than others processing of the rows of the loops, that uses cache of the execution environment better than others processing of the rows of the
@ -201,7 +201,7 @@ public static int[][] simpleMultiplication(int n, int[][] a, int[][] b) {
} }
``` ```
## Testing {#testing} {% include heading.html text="Testing" hash="testing" %}
To check, we take two square matrices `A=[1000×1000]` and `B=[1000×1000]`, filled with random numbers. To check, we take two square matrices `A=[1000×1000]` and `B=[1000×1000]`, filled with random numbers.
Take the minimum block size `[200×200]` elements. First, we compare the correctness of the implementation Take the minimum block size `[200×200]` elements. First, we compare the correctness of the implementation
@ -270,7 +270,7 @@ Hybrid algorithm | 196 | 177 | 156 | 205 | 154 | 165 | 133 | 118 | 132 | 134 ||
Nested loops | 165 | 164 | 168 | 167 | 168 | 168 | 170 | 179 | 173 | 168 || 169 Nested loops | 165 | 164 | 168 | 167 | 168 | 168 | 170 | 179 | 173 | 168 || 169
``` ```
## Comparing algorithms {#comparing-algorithms} {% include heading.html text="Comparing algorithms" hash="comparing-algorithms" %}
On an eight-core Linux x64 computer, execute the above test 100 times instead of 10. Take the minimum On an eight-core Linux x64 computer, execute the above test 100 times instead of 10. Take the minimum
block size `[brd=200]` elements. Change only `n` sizes of both matrices `A=[n×n]` and `B=[n×n]`. Get block size `[brd=200]` elements. Change only `n` sizes of both matrices `A=[n×n]` and `B=[n×n]`. Get

View file

@ -22,7 +22,7 @@ date: 2021.12.09
*Дальнейшая оптимизация: [Умножение матриц в параллельных потоках]({{ '/ru/2022/02/08/matrix-multiplication-parallel-streams.html' | relative_url }}).* *Дальнейшая оптимизация: [Умножение матриц в параллельных потоках]({{ '/ru/2022/02/08/matrix-multiplication-parallel-streams.html' | relative_url }}).*
## Построчный алгоритм {#row-wise-algorithm} {% include heading.html text="Построчный алгоритм" hash="row-wise-algorithm" %}
Внешний цикл обходит строки первой матрицы `L`, далее идёт цикл по *общей стороне* двух матриц `M` Внешний цикл обходит строки первой матрицы `L`, далее идёт цикл по *общей стороне* двух матриц `M`
и за ним цикл по колонкам второй матрицы `N`. Запись в результирующую матрицу происходит построчно, и за ним цикл по колонкам второй матрицы `N`. Запись в результирующую матрицу происходит построчно,
@ -55,7 +55,7 @@ public static int[][] matrixMultiplicationLMN(int l, int m, int n, int[][] a, in
} }
``` ```
## Послойный алгоритм {#layer-wise-algorithm} {% include heading.html text="Послойный алгоритм" hash="layer-wise-algorithm" %}
Внешний цикл обходит *общую сторону* двух матриц `M`, далее идёт цикл по строкам первой матрицы Внешний цикл обходит *общую сторону* двух матриц `M`, далее идёт цикл по строкам первой матрицы
`L` и за ним цикл по колонкам второй матрицы `N`. Запись в результирующую матрицу происходит слоями, `L` и за ним цикл по колонкам второй матрицы `N`. Запись в результирующую матрицу происходит слоями,
@ -88,7 +88,7 @@ public static int[][] matrixMultiplicationMLN(int l, int m, int n, int[][] a, in
} }
``` ```
### Прочие алгоритмы {#other-algorithms} {% include heading.html text="Прочие алгоритмы" hash="other-algorithms" type="3" %}
Обход колонок второй матрицы `N` происходит перед обходом *общей стороны* двух матриц `M` Обход колонок второй матрицы `N` происходит перед обходом *общей стороны* двух матриц `M`
и/или перед обходом строк первой матрицы `L`. и/или перед обходом строк первой матрицы `L`.
@ -137,7 +137,7 @@ public static int[][] matrixMultiplicationNML(int l, int m, int n, int[][] a, in
{% endcapture %} {% endcapture %}
{%- include collapsed_block.html summary="Код без комментариев" content=collapsed_md -%} {%- include collapsed_block.html summary="Код без комментариев" content=collapsed_md -%}
## Сравнение алгоритмов {#comparing-algorithms} {% include heading.html text="Сравнение алгоритмов" hash="comparing-algorithms" %}
Для проверки возьмём две матрицы `A=[500×700]` и `B=[700×450]`, заполненные случайными числами. Для проверки возьмём две матрицы `A=[500×700]` и `B=[700×450]`, заполненные случайными числами.
Сначала сравниваем между собой корректность реализации алгоритмов все полученные результаты Сначала сравниваем между собой корректность реализации алгоритмов все полученные результаты

View file

@ -19,7 +19,7 @@ date: 2022.02.08
*Дальнейшая оптимизация: [Алгоритм Винограда Штрассена]({{ '/ru/2022/02/10/winograd-strassen-algorithm.html' | relative_url }}).* *Дальнейшая оптимизация: [Алгоритм Винограда Штрассена]({{ '/ru/2022/02/10/winograd-strassen-algorithm.html' | relative_url }}).*
## Параллельный поток {#parallel-stream} {% include heading.html text="Параллельный поток" hash="parallel-stream" %}
Строки первой матрицы `L` обходим в параллельном режиме. Внутри каждого потока два вложенных цикла: Строки первой матрицы `L` обходим в параллельном режиме. Внутри каждого потока два вложенных цикла:
по *общей стороне* двух матриц `M` и по колонкам второй матрицы `N`. Обработка строк результирующей по *общей стороне* двух матриц `M` и по колонкам второй матрицы `N`. Обработка строк результирующей
@ -53,7 +53,7 @@ public static int[][] parallelMatrixMultiplication(int l, int m, int n, int[][]
} }
``` ```
## Три вложенных цикла {#three-nested-loops} {% include heading.html text="Три вложенных цикла" hash="three-nested-loops" %}
Возьмём оптимизированный вариант алгоритма, который лучше прочих использует кеш среды выполнения. Возьмём оптимизированный вариант алгоритма, который лучше прочих использует кеш среды выполнения.
Внешний цикл обходит строки первой матрицы `L`, далее идёт цикл по *общей стороне* двух матриц `M` Внешний цикл обходит строки первой матрицы `L`, далее идёт цикл по *общей стороне* двух матриц `M`
@ -87,7 +87,7 @@ public static int[][] sequentialMatrixMultiplication(int l, int m, int n, int[][
} }
``` ```
## Тестирование {#testing} {% include heading.html text="Тестирование" hash="testing" %}
Для проверки возьмём две матрицы: `A=[900×1000]` и `B=[1000×750]`, заполненные случайными числами. Для проверки возьмём две матрицы: `A=[900×1000]` и `B=[1000×750]`, заполненные случайными числами.
Сначала сравниваем между собой корректность реализации двух алгоритмов произведения матриц Сначала сравниваем между собой корректность реализации двух алгоритмов произведения матриц
@ -155,7 +155,7 @@ private static void benchmark(String title, int steps, Runnable runnable) {
Циклы | 1357 | 530 | 551 | 569 | 535 | 538 | 525 | 517 | 518 | 514 || 615 Циклы | 1357 | 530 | 551 | 569 | 535 | 538 | 525 | 517 | 518 | 514 || 615
``` ```
## Сравнение алгоритмов {#comparing-algorithms} {% include heading.html text="Сравнение алгоритмов" hash="comparing-algorithms" %}
На восьмиядерном компьютере Linux x64 создаём для тестов виртуальную машину Windows x64. При На восьмиядерном компьютере Linux x64 создаём для тестов виртуальную машину Windows x64. При
прочих равных условиях в настройках меняем количество процессоров. Запускаем вышеописанный прочих равных условиях в настройках меняем количество процессоров. Запускаем вышеописанный

View file

@ -24,7 +24,7 @@ date: 2022.02.10
*Алгоритм на трёх вложенных циклах: [Оптимизация умножения матриц]({{ '/ru/2021/12/09/optimizing-matrix-multiplication.html' | relative_url }}).* *Алгоритм на трёх вложенных циклах: [Оптимизация умножения матриц]({{ '/ru/2021/12/09/optimizing-matrix-multiplication.html' | relative_url }}).*
## Описание алгоритма {#algorithm-description} {% include heading.html text="Описание алгоритма" hash="algorithm-description" %}
Матрицы должны быть одинакового размера. Разделяем каждую матрицу на 4 равных блока. Блоки должны быть Матрицы должны быть одинакового размера. Разделяем каждую матрицу на 4 равных блока. Блоки должны быть
квадратными, поэтому если это не так, тогда сначала дополняем матрицы нулевыми строками и столбцами, квадратными, поэтому если это не так, тогда сначала дополняем матрицы нулевыми строками и столбцами,
@ -53,7 +53,7 @@ alt="{\displaystyle{\begin{aligned}T_{1}&=P_{1}+P_{2};\\T_{2}&=T_{1}+P_{4}.\end{
{% include image_svg.html src="/img/sums3.svg" style="width:240pt; height:33pt;" {% include image_svg.html src="/img/sums3.svg" style="width:240pt; height:33pt;"
alt="{\displaystyle{\begin{pmatrix}C_{11}&C_{12}\\C_{21}&C_{22}\end{pmatrix}}={\begin{pmatrix}P_{2}+P_{3}&T_{1}+P_{5}+P_{6}\\T_{2}-P_{7}&T_{2}+P_{5}\end{pmatrix}}.}" %} alt="{\displaystyle{\begin{pmatrix}C_{11}&C_{12}\\C_{21}&C_{22}\end{pmatrix}}={\begin{pmatrix}P_{2}+P_{3}&T_{1}+P_{5}+P_{6}\\T_{2}-P_{7}&T_{2}+P_{5}\end{pmatrix}}.}" %}
## Гибридный алгоритм {#hybrid-algorithm} {% include heading.html text="Гибридный алгоритм" hash="hybrid-algorithm" %}
Каждую матрицу `A` и `B` делим на 4 *равных* блока, при необходимости дополняем недостающие части Каждую матрицу `A` и `B` делим на 4 *равных* блока, при необходимости дополняем недостающие части
нулями. Выполняем 15 сложений и 7 умножений над блоками получаем 4 блока матрицы `C`. Убираем нулями. Выполняем 15 сложений и 7 умножений над блоками получаем 4 блока матрицы `C`. Убираем
@ -165,7 +165,7 @@ private static int[][] putQuadrants(int m, int n,
{% endcapture %} {% endcapture %}
{%- include collapsed_block.html summary="Вспомогательные методы" content=collapsed_md -%} {%- include collapsed_block.html summary="Вспомогательные методы" content=collapsed_md -%}
## Вложенные циклы {#nested-loops} {% include heading.html text="Вложенные циклы" hash="nested-loops" %}
Для дополнения предыдущего алгоритма и для сравнения с ним же будем использовать *оптимизированный* Для дополнения предыдущего алгоритма и для сравнения с ним же будем использовать *оптимизированный*
вариант вложенных циклов, который лучше прочих использует кеш среды выполнения обработка строк вариант вложенных циклов, который лучше прочих использует кеш среды выполнения обработка строк
@ -197,7 +197,7 @@ public static int[][] simpleMultiplication(int n, int[][] a, int[][] b) {
} }
``` ```
## Тестирование {#testing} {% include heading.html text="Тестирование" hash="testing" %}
Для проверки возьмём две квадратные матрицы `A=[1000×1000]` и `B=[1000×1000]`, заполненные случайными Для проверки возьмём две квадратные матрицы `A=[1000×1000]` и `B=[1000×1000]`, заполненные случайными
числами. Минимальный размер блока возьмём `[200×200]` элементов. Сначала сравниваем между собой числами. Минимальный размер блока возьмём `[200×200]` элементов. Сначала сравниваем между собой
@ -266,7 +266,7 @@ private static void benchmark(String title, int steps, Runnable runnable) {
Вложенные циклы | 165 | 164 | 168 | 167 | 168 | 168 | 170 | 179 | 173 | 168 || 169 Вложенные циклы | 165 | 164 | 168 | 167 | 168 | 168 | 170 | 179 | 173 | 168 || 169
``` ```
## Сравнение алгоритмов {#comparing-algorithms} {% include heading.html text="Сравнение алгоритмов" hash="comparing-algorithms" %}
На восьмиядерном компьютере Linux x64 запускаем вышеописанный тест 100 раз вместо 10. Минимальный На восьмиядерном компьютере Linux x64 запускаем вышеописанный тест 100 раз вместо 10. Минимальный
размер блока берём `[brd=200]`. Изменяем только `n` размеры обеих матриц `A=[n×n]` и `B=[n×n]`. размер блока берём `[brd=200]`. Изменяем только `n` размеры обеих матриц `A=[n×n]` и `B=[n×n]`.