2023-09-30
This commit is contained in:
parent
ed71e6823d
commit
6f960bda29
8 changed files with 30 additions and 30 deletions
|
@ -7,9 +7,9 @@ url: "https://pomodoro3.mircloud.ru"
|
|||
# подпапка этой сборки для относительных URLs
|
||||
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: ""
|
||||
# часовой пояс для формата даты ISO-8601
|
||||
|
|
|
@ -7,9 +7,9 @@ url: "https://pomodoro3.mircloud.ru"
|
|||
# подпапка этой сборки для относительных URLs
|
||||
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"
|
||||
# часовой пояс для формата даты ISO-8601
|
||||
|
|
|
@ -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 }}).*
|
||||
|
||||
## 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*
|
||||
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
|
||||
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
|
||||
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 %}
|
||||
{%- 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
|
||||
compare the correctness of the implementation of the algorithms — all results obtained must match.
|
||||
|
|
|
@ -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 }}).*
|
||||
|
||||
## 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:
|
||||
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
|
||||
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.
|
||||
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
|
||||
```
|
||||
|
||||
## 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
|
||||
other things being equal, in the settings, we change the number of processors. We run the
|
||||
|
|
|
@ -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 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
|
||||
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;"
|
||||
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
|
||||
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 %}
|
||||
{%- 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
|
||||
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.
|
||||
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
|
||||
```
|
||||
|
||||
## 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
|
||||
block size `[brd=200]` elements. Change only `n` — sizes of both matrices `A=[n×n]` and `B=[n×n]`. Get
|
||||
|
|
|
@ -22,7 +22,7 @@ date: 2021.12.09
|
|||
|
||||
*Дальнейшая оптимизация: [Умножение матриц в параллельных потоках]({{ '/ru/2022/02/08/matrix-multiplication-parallel-streams.html' | relative_url }}).*
|
||||
|
||||
## Построчный алгоритм {#row-wise-algorithm}
|
||||
{% include heading.html text="Построчный алгоритм" hash="row-wise-algorithm" %}
|
||||
|
||||
Внешний цикл обходит строки первой матрицы `L`, далее идёт цикл по *общей стороне* двух матриц `M`
|
||||
и за ним цикл по колонкам второй матрицы `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`, далее идёт цикл по строкам первой матрицы
|
||||
`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`
|
||||
и/или перед обходом строк первой матрицы `L`.
|
||||
|
@ -137,7 +137,7 @@ public static int[][] matrixMultiplicationNML(int l, int m, int n, int[][] a, in
|
|||
{% endcapture %}
|
||||
{%- include collapsed_block.html summary="Код без комментариев" content=collapsed_md -%}
|
||||
|
||||
## Сравнение алгоритмов {#comparing-algorithms}
|
||||
{% include heading.html text="Сравнение алгоритмов" hash="comparing-algorithms" %}
|
||||
|
||||
Для проверки возьмём две матрицы `A=[500×700]` и `B=[700×450]`, заполненные случайными числами.
|
||||
Сначала сравниваем между собой корректность реализации алгоритмов — все полученные результаты
|
||||
|
|
|
@ -19,7 +19,7 @@ date: 2022.02.08
|
|||
|
||||
*Дальнейшая оптимизация: [Алгоритм Винограда — Штрассена]({{ '/ru/2022/02/10/winograd-strassen-algorithm.html' | relative_url }}).*
|
||||
|
||||
## Параллельный поток {#parallel-stream}
|
||||
{% include heading.html text="Параллельный поток" hash="parallel-stream" %}
|
||||
|
||||
Строки первой матрицы `L` обходим в параллельном режиме. Внутри каждого потока два вложенных цикла:
|
||||
по *общей стороне* двух матриц `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`
|
||||
|
@ -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]`, заполненные случайными числами.
|
||||
Сначала сравниваем между собой корректность реализации двух алгоритмов — произведения матриц
|
||||
|
@ -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
|
||||
```
|
||||
|
||||
## Сравнение алгоритмов {#comparing-algorithms}
|
||||
{% include heading.html text="Сравнение алгоритмов" hash="comparing-algorithms" %}
|
||||
|
||||
На восьмиядерном компьютере Linux x64 создаём для тестов виртуальную машину Windows x64. При
|
||||
прочих равных условиях в настройках меняем количество процессоров. Запускаем вышеописанный
|
||||
|
|
|
@ -24,7 +24,7 @@ date: 2022.02.10
|
|||
|
||||
*Алгоритм на трёх вложенных циклах: [Оптимизация умножения матриц]({{ '/ru/2021/12/09/optimizing-matrix-multiplication.html' | relative_url }}).*
|
||||
|
||||
## Описание алгоритма {#algorithm-description}
|
||||
{% include heading.html text="Описание алгоритма" hash="algorithm-description" %}
|
||||
|
||||
Матрицы должны быть одинакового размера. Разделяем каждую матрицу на 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;"
|
||||
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 *равных* блока, при необходимости дополняем недостающие части
|
||||
нулями. Выполняем 15 сложений и 7 умножений над блоками — получаем 4 блока матрицы `C`. Убираем
|
||||
|
@ -165,7 +165,7 @@ private static int[][] putQuadrants(int m, int n,
|
|||
{% endcapture %}
|
||||
{%- 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]`, заполненные случайными
|
||||
числами. Минимальный размер блока возьмём `[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
|
||||
```
|
||||
|
||||
## Сравнение алгоритмов {#comparing-algorithms}
|
||||
{% include heading.html text="Сравнение алгоритмов" hash="comparing-algorithms" %}
|
||||
|
||||
На восьмиядерном компьютере Linux x64 запускаем вышеописанный тест 100 раз вместо 10. Минимальный
|
||||
размер блока берём `[brd=200]`. Изменяем только `n` — размеры обеих матриц `A=[n×n]` и `B=[n×n]`.
|
||||
|
|
Loading…
Add table
Reference in a new issue