Compare commits

..

10 commits

Author SHA1 Message Date
0054f7245c 2024-12-29 2024-12-29 10:39:47 +03:00
0cba400c21 2024-09-30 2024-10-01 18:02:31 +03:00
00acb3beeb 2024-08-31 2024-09-01 08:46:26 +03:00
a700572723 2024-07-31 2024-07-31 21:11:20 +03:00
fafb270621 2024-03-31 2024-03-31 02:14:43 +03:00
29d17ed877 2024-02-29 2024-02-29 22:56:43 +03:00
8dcb9dbd1e 2023-12-30 2023-12-30 23:55:12 +03:00
d9e59c1688 2023-11-30 2023-12-17 09:50:15 +03:00
6f960bda29 2023-09-30 2023-12-17 08:49:19 +03:00
ed71e6823d 2023-08-31 2023-12-17 08:22:17 +03:00
16 changed files with 125 additions and 117 deletions

View file

@ -3,9 +3,6 @@
<pre> <pre>
<a href='.'>.</a> <a href='.'>.</a>
├─ <a href='jekyll_site'>jekyll_site</a> ├─ <a href='jekyll_site'>jekyll_site</a>
│ ├─ <a href='jekyll_site/_includes'>_includes</a>
│ │ ├─ <a href='jekyll_site/_includes/counters_body.html'>counters_body.html</a>
│ │ └─ <a href='jekyll_site/_includes/counters_head.html'>counters_head.html</a>
│ ├─ <a href='jekyll_site/en'>en</a> │ ├─ <a href='jekyll_site/en'>en</a>
│ │ ├─ <a href='jekyll_site/en/2021'>2021</a>/<a href='jekyll_site/en/2021/12'>12</a> │ │ ├─ <a href='jekyll_site/en/2021'>2021</a>/<a href='jekyll_site/en/2021/12'>12</a>
│ │ │ ├─ <a href='jekyll_site/en/2021/12/10'>10</a>/<a href='jekyll_site/en/2021/12/10/optimizing-matrix-multiplication.md'>optimizing-matrix-multiplication.md</a> │ │ │ ├─ <a href='jekyll_site/en/2021/12/10'>10</a>/<a href='jekyll_site/en/2021/12/10/optimizing-matrix-multiplication.md'>optimizing-matrix-multiplication.md</a>

View file

@ -1,4 +1,4 @@
© Головин Г.Г., 2021-2023 © Головин Г.Г., 2021-2024
Опубликовано под [Открытой лицензией 1.1](OPEN_LICENSE.txt) Опубликовано под [Открытой лицензией 1.1](OPEN_LICENSE.txt)
@ -8,7 +8,7 @@
--- ---
© Golovin G.G., translation from Russian, 2021-2023 © Golovin G.G., translation from Russian, 2021-2024
Published under the [Open License 1.1](OPEN_LICENSE.txt) Published under the [Open License 1.1](OPEN_LICENSE.txt)

View file

@ -1,5 +1,5 @@
## Исходные тексты ## Исходные тексты
- Используемые форматы — Markdown, Liquid, YAML. - Используемые форматы — Markdown, Liquid, YAML.
- Инструмент сборки — Jekyll с помидорными темами оформления. - Инструмент сборки — Jekyll и помидорные темы оформления.
- Управление процессами — Bash скрипты. - Управление процессами — Bash скрипты.

View file

@ -1,37 +1,34 @@
#!/bin/bash #!/bin/bash
echo "Сборка сайта в двух помидорных темах и оптимизация результатов." echo "Сборка сайта в двух помидорных темах и оптимизация результатов."
milliseconds=$(date '+%s%3N') time_ms="$(date '+%s%3N')"
rm -rf _site # удаление каталогов предыдущей сборки, если таковые имеются
rm -rf _site_older find . -maxdepth 1 -type d -name "_site*" -exec rm -rf {} \;
rm -rf _site_color # сборка сайта в двух помидорных темах
echo "Сборка старого помидора." function jekyll_build {
mkdir -p _site_older case "$1" in
cp -r jekyll_site/_includes _site_older "older") echo "Сборка старого помидора." ;;
cp -r jekyll_site/ru _site_older "color") echo "Сборка цветного помидора." ;;
cp -r jekyll_site/en _site_older *) return ;; # две помидорные темы оформления
cp -r jekyll_site/ru/index.md _site_older esac
cp -r jekyll_site/_config_older.yml _site_older/_config.yml mkdir -p "_site_$1"
cp -r jekyll_site/Gemfile_older _site_older/Gemfile cp -r "jekyll_site/ru" "_site_$1"
cd _site_older || exit cp -r "jekyll_site/en" "_site_$1"
jekyll build cp -r "jekyll_site/ru/index.md" "_site_$1"
cp -r _site .. cp -r "jekyll_site/_config_$1.yml" "_site_$1/_config.yml"
cd .. cp -r "jekyll_site/Gemfile_$1" "_site_$1/Gemfile"
echo "Сборка цветного помидора." cd "_site_$1" || return
mkdir -p _site_color jekyll build --disable-disk-cache --quiet
cp -r jekyll_site/_includes _site_color }
cp -r jekyll_site/ru _site_color export -f jekyll_build
cp -r jekyll_site/en _site_color # запуск параллельной сборки сайта в двух помидорных темах оформления
cp -r jekyll_site/ru/index.md _site_color printf 'jekyll_build "%s"\0' {older,color} | xargs -n1 -0 -P0 bash -c
cp -r jekyll_site/_config_color.yml _site_color/_config.yml # объединение двух сборок
cp -r jekyll_site/Gemfile_color _site_color/Gemfile cp -r _site_older/_site .
cd _site_color || exit cp -r _site_color/_site ./_site/color
jekyll build # копирование без сборки
cp -r _site ../_site/color
cd ..
echo "Копирование без сборки."
cp -r jekyll_site/img _site cp -r jekyll_site/img _site
cp -r jekyll_site/robots.txt _site cp -r jekyll_site/robots.txt _site
echo "Оптимизация собранного контента." # оптимизация собранного контента
cd _site || exit cd _site || exit
cp -r assets/* . cp -r assets/* .
rm -r assets rm -r assets
@ -39,13 +36,19 @@ rm -r color/assets/favicon.ico
cp -r color/assets/* . cp -r color/assets/* .
rm -r color/assets rm -r color/assets
rm -r color/404.html rm -r color/404.html
find . -type f -name '*.html' | sort -r | while read -r file; do rm -r color/return.html
sed -i 's/layout-padding=""/layout-padding/g' "$file" # шаблоны для оптимизации ряда тегов
sed -i 's/ class="language-plaintext highlighter-rouge"//g' "$file" expr+=('s|layout-padding=""|layout-padding|g')
sed -i 's/ class="language-java highlighter-rouge"//g' "$file" expr+=('s| class="language-plaintext highlighter-rouge"||g')
sed -i 's/<div><div class="highlight"><pre class="highlight">/<div class="highlight"><pre class="highlight">/g' "$file" expr+=('s| class="language-java highlighter-rouge"||g')
sed -i 's/<\/code><\/pre><\/div><\/div>/<\/code><\/pre><\/div>/g' "$file" expr+=('s|<div><div class="highlight">|<div class="highlight">|g')
sed -i 's/<hr \/>/<hr>/g' "$file" expr+=('s|</pre></div></div>|</pre></div>|g')
sed -i -r 's/<img(.+) \/>/<img\1>/g' "$file" expr+=('s|<hr />|<hr>|g')
done expr+=('s|<img(.+) />|<img\1>|g')
echo "Время выполнения сборки: $(("$(date '+%s%3N')" - "$milliseconds")) мс." # запуск параллельной обработки собранных страниц и оптимизация ряда тегов
find . -type f -name "*.html" -printf '%p\0' | xargs -I{} -n1 -0 -P0 bash -c \
"echo 'Оптимизация: {}' && sed -i -E $(printf " -e '%s'" "${expr[@]}") '{}'"
# переход в корень сайта для каталогов без заглавной страницы
find . -type d -exec cp -n return.html {}/index.html \;
rm -r return.html
echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс."

View file

@ -1,18 +1,31 @@
# site parameters # название сайта для подписи в футере
name: "Код с комментариями" name: "Код с комментариями"
# подпись в футере для переведённых страниц
name_translated: "Code with comments" name_translated: "Code with comments"
# URL адрес сайта, включая протокол
url: "https://pomodoro3.mircloud.ru" url: "https://pomodoro3.mircloud.ru"
# подпапка этой сборки для относительных URL-ов
baseurl: "/color" baseurl: "/color"
homepage_url: "https://git.org.ru/pomodoro/3" # ссылка в верхнем левом углу заглавных страниц
homepage_name: "GIT.ORG.RU" homepage_url: "https://gitea.com/pomodoro/3"
# представление ссылки
homepage_name: "GITEA"
# подпапка альтернативной сборки
older_tomato_baseurl: "" older_tomato_baseurl: ""
# часовой пояс для формата даты ISO-8601
timezone: "Europe/Moscow" timezone: "Europe/Moscow"
# имя автора для SEO-разметки и подписи в футере
author: "Головин Г.Г." author: "Головин Г.Г."
# транслитерация имени автора для переведённых страниц
author_translated: "Golovin G.G." author_translated: "Golovin G.G."
# дополнение к подписи в футере для переведённых страниц
translation_caption: "translation from Russian" translation_caption: "translation from Russian"
# build parameters # номера счётчиков для страниц
disable_disk_cache: true live_internet: "pomodoro"
yandex_metrika: "95699483"
# тема оформления для сборки
theme: color-tomato-theme theme: color-tomato-theme
# макет для сборки
defaults: defaults:
- scope: - scope:
path: "" path: ""

View file

@ -1,18 +1,31 @@
# site parameters # название сайта для подписи в футере
name: "Код с комментариями" name: "Код с комментариями"
# подпись в футере для переведённых страниц
name_translated: "Code with comments" name_translated: "Code with comments"
# URL адрес сайта, включая протокол
url: "https://pomodoro3.mircloud.ru" url: "https://pomodoro3.mircloud.ru"
# подпапка этой сборки для относительных URL-ов
baseurl: "" baseurl: ""
homepage_url: "https://git.org.ru/pomodoro/3" # ссылка в верхнем левом углу заглавных страниц
homepage_name: "GIT.ORG.RU" homepage_url: "https://gitea.com/pomodoro/3"
# представление ссылки
homepage_name: "GITEA"
# подпапка альтернативной сборки
color_tomato_baseurl: "/color" color_tomato_baseurl: "/color"
# часовой пояс для формата даты ISO-8601
timezone: "Europe/Moscow" timezone: "Europe/Moscow"
# имя автора для SEO-разметки и подписи в футере
author: "Головин Г.Г." author: "Головин Г.Г."
# транслитерация имени автора для переведённых страниц
author_translated: "Golovin G.G." author_translated: "Golovin G.G."
# дополнение к подписи в футере для переведённых страниц
translation_caption: "translation from Russian" translation_caption: "translation from Russian"
# build parameters # номера счётчиков для страниц
disable_disk_cache: true live_internet: "pomodoro"
yandex_metrika: "95699483"
# тема оформления для сборки
theme: older-tomato-theme theme: older-tomato-theme
# макет для сборки
defaults: defaults:
- scope: - scope:
path: "" path: ""

View file

@ -1,2 +0,0 @@
<noscript><div><img src="https://mc.yandex.ru/watch/87058815" style="position:absolute; left:-9999px;" alt=""></div></noscript>
<!-- /Yandex.Metrika counter -->

View file

@ -1,16 +0,0 @@
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-148X3KY8JP"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-148X3KY8JP');
</script>
<!-- Yandex.Metrika counter -->
<script>
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();for(var j=0;j<document.scripts.length;j++){if(document.scripts[j].src===r){return;}}
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window,document,"script","https://mc.yandex.ru/metrika/tag.js","ym");
ym(87058815,"init",{clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true});
</script>

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
@ -101,13 +101,13 @@ public static int[][] multiplyMatrices(int n, int brd, int[][] a, int[][] b) {
// multiplication of blocks in parallel streams // multiplication of blocks in parallel streams
IntStream.range(0, 7).parallel().forEach(i -> { IntStream.range(0, 7).parallel().forEach(i -> {
switch (i) { // recursive calls switch (i) { // recursive calls
case 0: p[i] = multiplyMatrices(m, brd, s2, s6); break; case 0 -> p[i] = multiplyMatrices(m, brd, s2, s6);
case 1: p[i] = multiplyMatrices(m, brd, a11, b11); break; case 1 -> p[i] = multiplyMatrices(m, brd, a11, b11);
case 2: p[i] = multiplyMatrices(m, brd, a12, b21); break; case 2 -> p[i] = multiplyMatrices(m, brd, a12, b21);
case 3: p[i] = multiplyMatrices(m, brd, s3, s7); break; case 3 -> p[i] = multiplyMatrices(m, brd, s3, s7);
case 4: p[i] = multiplyMatrices(m, brd, s1, s5); break; case 4 -> p[i] = multiplyMatrices(m, brd, s1, s5);
case 5: p[i] = multiplyMatrices(m, brd, s4, b22); break; case 5 -> p[i] = multiplyMatrices(m, brd, s4, b22);
case 6: p[i] = multiplyMatrices(m, brd, a22, s8); break; case 6 -> p[i] = multiplyMatrices(m, brd, a22, s8);
} }
}); });
// summation of blocks // summation of blocks
@ -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`. Убираем
@ -97,13 +97,13 @@ public static int[][] multiplyMatrices(int n, int brd, int[][] a, int[][] b) {
// перемножаем блоки в параллельных потоках // перемножаем блоки в параллельных потоках
IntStream.range(0, 7).parallel().forEach(i -> { IntStream.range(0, 7).parallel().forEach(i -> {
switch (i) { // рекурсивные вызовы switch (i) { // рекурсивные вызовы
case 0: p[i] = multiplyMatrices(m, brd, s2, s6); break; case 0 -> p[i] = multiplyMatrices(m, brd, s2, s6);
case 1: p[i] = multiplyMatrices(m, brd, a11, b11); break; case 1 -> p[i] = multiplyMatrices(m, brd, a11, b11);
case 2: p[i] = multiplyMatrices(m, brd, a12, b21); break; case 2 -> p[i] = multiplyMatrices(m, brd, a12, b21);
case 3: p[i] = multiplyMatrices(m, brd, s3, s7); break; case 3 -> p[i] = multiplyMatrices(m, brd, s3, s7);
case 4: p[i] = multiplyMatrices(m, brd, s1, s5); break; case 4 -> p[i] = multiplyMatrices(m, brd, s1, s5);
case 5: p[i] = multiplyMatrices(m, brd, s4, b22); break; case 5 -> p[i] = multiplyMatrices(m, brd, s4, b22);
case 6: p[i] = multiplyMatrices(m, brd, a22, s8); break; case 6 -> p[i] = multiplyMatrices(m, brd, a22, s8);
} }
}); });
// суммируем блоки // суммируем блоки
@ -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]`.

View file

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
echo "Подготовка архива для последующего развёртывания." echo "Создание архива для последующего развёртывания."
cd _site || exit cd _site || exit
rm -rf ../pomodoro3.zip rm -rf ../pomodoro3.zip
7z a ../pomodoro3.zip ./* 7z a ../pomodoro3.zip . | grep -E '\S'

View file

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash
echo "Локальное развёртывание для проверки корректности сборки." echo "Локальное развёртывание для проверки корректности сборки."
jekyll serve --skip-initial-build --disable-disk-cache --host localhost jekyll serve --skip-initial-build --no-watch --disable-disk-cache --host localhost
echo "Адрес сервера: http://localhost:4000" echo "Адрес сервера: http://localhost:4000"