Compare commits

..

No commits in common. "0054f7245c4b55262f223515cbae7b4d4be6c985" and "6e77099ed2a7e10e83719283c0b0015edc345e08" have entirely different histories.

16 changed files with 117 additions and 125 deletions

View file

@ -3,6 +3,9 @@
<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-2024 © Головин Г.Г., 2021-2023
Опубликовано под [Открытой лицензией 1.1](OPEN_LICENSE.txt) Опубликовано под [Открытой лицензией 1.1](OPEN_LICENSE.txt)
@ -8,7 +8,7 @@
--- ---
© Golovin G.G., translation from Russian, 2021-2024 © Golovin G.G., translation from Russian, 2021-2023
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,34 +1,37 @@
#!/bin/bash #!/bin/bash
echo "Сборка сайта в двух помидорных темах и оптимизация результатов." echo "Сборка сайта в двух помидорных темах и оптимизация результатов."
time_ms="$(date '+%s%3N')" milliseconds=$(date '+%s%3N')
# удаление каталогов предыдущей сборки, если таковые имеются rm -rf _site
find . -maxdepth 1 -type d -name "_site*" -exec rm -rf {} \; rm -rf _site_older
# сборка сайта в двух помидорных темах rm -rf _site_color
function jekyll_build { echo "Сборка старого помидора."
case "$1" in mkdir -p _site_older
"older") echo "Сборка старого помидора." ;; cp -r jekyll_site/_includes _site_older
"color") echo "Сборка цветного помидора." ;; cp -r jekyll_site/ru _site_older
*) return ;; # две помидорные темы оформления cp -r jekyll_site/en _site_older
esac cp -r jekyll_site/ru/index.md _site_older
mkdir -p "_site_$1" cp -r jekyll_site/_config_older.yml _site_older/_config.yml
cp -r "jekyll_site/ru" "_site_$1" cp -r jekyll_site/Gemfile_older _site_older/Gemfile
cp -r "jekyll_site/en" "_site_$1" cd _site_older || exit
cp -r "jekyll_site/ru/index.md" "_site_$1" jekyll build
cp -r "jekyll_site/_config_$1.yml" "_site_$1/_config.yml" cp -r _site ..
cp -r "jekyll_site/Gemfile_$1" "_site_$1/Gemfile" cd ..
cd "_site_$1" || return echo "Сборка цветного помидора."
jekyll build --disable-disk-cache --quiet mkdir -p _site_color
} cp -r jekyll_site/_includes _site_color
export -f jekyll_build cp -r jekyll_site/ru _site_color
# запуск параллельной сборки сайта в двух помидорных темах оформления cp -r jekyll_site/en _site_color
printf 'jekyll_build "%s"\0' {older,color} | xargs -n1 -0 -P0 bash -c cp -r jekyll_site/ru/index.md _site_color
# объединение двух сборок cp -r jekyll_site/_config_color.yml _site_color/_config.yml
cp -r _site_older/_site . cp -r jekyll_site/Gemfile_color _site_color/Gemfile
cp -r _site_color/_site ./_site/color cd _site_color || exit
# копирование без сборки 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
@ -36,19 +39,13 @@ 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
rm -r color/return.html find . -type f -name '*.html' | sort -r | while read -r file; do
# шаблоны для оптимизации ряда тегов sed -i 's/layout-padding=""/layout-padding/g' "$file"
expr+=('s|layout-padding=""|layout-padding|g') sed -i 's/ class="language-plaintext highlighter-rouge"//g' "$file"
expr+=('s| class="language-plaintext highlighter-rouge"||g') sed -i 's/ class="language-java highlighter-rouge"//g' "$file"
expr+=('s| class="language-java highlighter-rouge"||g') sed -i 's/<div><div class="highlight"><pre class="highlight">/<div class="highlight"><pre class="highlight">/g' "$file"
expr+=('s|<div><div class="highlight">|<div class="highlight">|g') sed -i 's/<\/code><\/pre><\/div><\/div>/<\/code><\/pre><\/div>/g' "$file"
expr+=('s|</pre></div></div>|</pre></div>|g') sed -i 's/<hr \/>/<hr>/g' "$file"
expr+=('s|<hr />|<hr>|g') sed -i -r 's/<img(.+) \/>/<img\1>/g' "$file"
expr+=('s|<img(.+) />|<img\1>|g') done
# запуск параллельной обработки собранных страниц и оптимизация ряда тегов 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,31 +1,18 @@
# название сайта для подписи в футере # 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_url: "https://gitea.com/pomodoro/3" homepage_name: "GIT.ORG.RU"
# представление ссылки
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
live_internet: "pomodoro" disable_disk_cache: true
yandex_metrika: "95699483"
# тема оформления для сборки
theme: color-tomato-theme theme: color-tomato-theme
# макет для сборки
defaults: defaults:
- scope: - scope:
path: "" path: ""

View file

@ -1,31 +1,18 @@
# название сайта для подписи в футере # 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_url: "https://gitea.com/pomodoro/3" homepage_name: "GIT.ORG.RU"
# представление ссылки
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
live_internet: "pomodoro" disable_disk_cache: true
yandex_metrika: "95699483"
# тема оформления для сборки
theme: older-tomato-theme theme: older-tomato-theme
# макет для сборки
defaults: defaults:
- scope: - scope:
path: "" path: ""

View file

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

View file

@ -0,0 +1,16 @@
<!-- 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 }}).*
{% include heading.html text="Row-wise algorithm" hash="row-wise-algorithm" %} ## Row-wise algorithm {#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
} }
``` ```
{% include heading.html text="Layer-wise algorithm" hash="layer-wise-algorithm" %} ## Layer-wise algorithm {#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
} }
``` ```
{% include heading.html text="Other algorithms" hash="other-algorithms" type="3" %} ### Other algorithms {#other-algorithms}
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 -%}
{% include heading.html text="Comparing algorithms" hash="comparing-algorithms" %} ## Comparing algorithms {#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 }}).*
{% include heading.html text="Parallel stream" hash="parallel-stream" %} ## Parallel stream {#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[][]
} }
``` ```
{% include heading.html text="Three nested loops" hash="three-nested-loops" %} ## Three nested loops {#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[][
} }
``` ```
{% include heading.html text="Testing" hash="testing" %} ## Testing {#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
``` ```
{% include heading.html text="Comparing algorithms" hash="comparing-algorithms" %} ## Comparing algorithms {#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 }}).*
{% include heading.html text="Algorithm description" hash="algorithm-description" %} ## Algorithm description {#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}}.}" %}
{% include heading.html text="Hybrid algorithm" hash="hybrid-algorithm" %} ## Hybrid algorithm {#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); case 0: p[i] = multiplyMatrices(m, brd, s2, s6); break;
case 1 -> p[i] = multiplyMatrices(m, brd, a11, b11); case 1: p[i] = multiplyMatrices(m, brd, a11, b11); break;
case 2 -> p[i] = multiplyMatrices(m, brd, a12, b21); case 2: p[i] = multiplyMatrices(m, brd, a12, b21); break;
case 3 -> p[i] = multiplyMatrices(m, brd, s3, s7); case 3: p[i] = multiplyMatrices(m, brd, s3, s7); break;
case 4 -> p[i] = multiplyMatrices(m, brd, s1, s5); case 4: p[i] = multiplyMatrices(m, brd, s1, s5); break;
case 5 -> p[i] = multiplyMatrices(m, brd, s4, b22); case 5: p[i] = multiplyMatrices(m, brd, s4, b22); break;
case 6 -> p[i] = multiplyMatrices(m, brd, a22, s8); case 6: p[i] = multiplyMatrices(m, brd, a22, s8); break;
} }
}); });
// 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 -%}
{% include heading.html text="Nested loops" hash="nested-loops" %} ## Nested loops {#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) {
} }
``` ```
{% include heading.html text="Testing" hash="testing" %} ## Testing {#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
``` ```
{% include heading.html text="Comparing algorithms" hash="comparing-algorithms" %} ## Comparing algorithms {#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 }}).*
{% include heading.html text="Построчный алгоритм" hash="row-wise-algorithm" %} ## Построчный алгоритм {#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
} }
``` ```
{% include heading.html text="Послойный алгоритм" hash="layer-wise-algorithm" %} ## Послойный алгоритм {#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
} }
``` ```
{% include heading.html text="Прочие алгоритмы" hash="other-algorithms" type="3" %} ### Прочие алгоритмы {#other-algorithms}
Обход колонок второй матрицы `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 -%}
{% include heading.html text="Сравнение алгоритмов" hash="comparing-algorithms" %} ## Сравнение алгоритмов {#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 }}).*
{% include heading.html text="Параллельный поток" hash="parallel-stream" %} ## Параллельный поток {#parallel-stream}
Строки первой матрицы `L` обходим в параллельном режиме. Внутри каждого потока два вложенных цикла: Строки первой матрицы `L` обходим в параллельном режиме. Внутри каждого потока два вложенных цикла:
по *общей стороне* двух матриц `M` и по колонкам второй матрицы `N`. Обработка строк результирующей по *общей стороне* двух матриц `M` и по колонкам второй матрицы `N`. Обработка строк результирующей
@ -53,7 +53,7 @@ public static int[][] parallelMatrixMultiplication(int l, int m, int n, int[][]
} }
``` ```
{% include heading.html text="Три вложенных цикла" hash="three-nested-loops" %} ## Три вложенных цикла {#three-nested-loops}
Возьмём оптимизированный вариант алгоритма, который лучше прочих использует кеш среды выполнения. Возьмём оптимизированный вариант алгоритма, который лучше прочих использует кеш среды выполнения.
Внешний цикл обходит строки первой матрицы `L`, далее идёт цикл по *общей стороне* двух матриц `M` Внешний цикл обходит строки первой матрицы `L`, далее идёт цикл по *общей стороне* двух матриц `M`
@ -87,7 +87,7 @@ public static int[][] sequentialMatrixMultiplication(int l, int m, int n, int[][
} }
``` ```
{% include heading.html text="Тестирование" hash="testing" %} ## Тестирование {#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
``` ```
{% include heading.html text="Сравнение алгоритмов" hash="comparing-algorithms" %} ## Сравнение алгоритмов {#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 }}).*
{% include heading.html text="Описание алгоритма" hash="algorithm-description" %} ## Описание алгоритма {#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}}.}" %}
{% include heading.html text="Гибридный алгоритм" hash="hybrid-algorithm" %} ## Гибридный алгоритм {#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); case 0: p[i] = multiplyMatrices(m, brd, s2, s6); break;
case 1 -> p[i] = multiplyMatrices(m, brd, a11, b11); case 1: p[i] = multiplyMatrices(m, brd, a11, b11); break;
case 2 -> p[i] = multiplyMatrices(m, brd, a12, b21); case 2: p[i] = multiplyMatrices(m, brd, a12, b21); break;
case 3 -> p[i] = multiplyMatrices(m, brd, s3, s7); case 3: p[i] = multiplyMatrices(m, brd, s3, s7); break;
case 4 -> p[i] = multiplyMatrices(m, brd, s1, s5); case 4: p[i] = multiplyMatrices(m, brd, s1, s5); break;
case 5 -> p[i] = multiplyMatrices(m, brd, s4, b22); case 5: p[i] = multiplyMatrices(m, brd, s4, b22); break;
case 6 -> p[i] = multiplyMatrices(m, brd, a22, s8); case 6: p[i] = multiplyMatrices(m, brd, a22, s8); break;
} }
}); });
// суммируем блоки // суммируем блоки
@ -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 -%}
{% include heading.html text="Вложенные циклы" hash="nested-loops" %} ## Вложенные циклы {#nested-loops}
Для дополнения предыдущего алгоритма и для сравнения с ним же будем использовать *оптимизированный* Для дополнения предыдущего алгоритма и для сравнения с ним же будем использовать *оптимизированный*
вариант вложенных циклов, который лучше прочих использует кеш среды выполнения обработка строк вариант вложенных циклов, который лучше прочих использует кеш среды выполнения обработка строк
@ -197,7 +197,7 @@ public static int[][] simpleMultiplication(int n, int[][] a, int[][] b) {
} }
``` ```
{% include heading.html text="Тестирование" hash="testing" %} ## Тестирование {#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
``` ```
{% include heading.html text="Сравнение алгоритмов" hash="comparing-algorithms" %} ## Сравнение алгоритмов {#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 . | grep -E '\S' 7z a ../pomodoro3.zip ./*

View file

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