Compare commits
10 commits
6e77099ed2
...
0054f7245c
Author | SHA1 | Date | |
---|---|---|---|
0054f7245c | |||
0cba400c21 | |||
00acb3beeb | |||
a700572723 | |||
fafb270621 | |||
29d17ed877 | |||
8dcb9dbd1e | |||
d9e59c1688 | |||
6f960bda29 | |||
ed71e6823d |
16 changed files with 125 additions and 117 deletions
|
@ -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>
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
## Исходные тексты
|
## Исходные тексты
|
||||||
|
|
||||||
- Используемые форматы — Markdown, Liquid, YAML.
|
- Используемые форматы — Markdown, Liquid, YAML.
|
||||||
- Инструмент сборки — Jekyll с помидорными темами оформления.
|
- Инструмент сборки — Jekyll и помидорные темы оформления.
|
||||||
- Управление процессами — Bash скрипты.
|
- Управление процессами — Bash скрипты.
|
||||||
|
|
83
build.sh
83
build.sh
|
@ -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)) мс."
|
||||||
|
|
|
@ -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: ""
|
||||||
|
|
|
@ -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: ""
|
||||||
|
|
|
@ -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 -->
|
|
|
@ -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>
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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]`, заполненные случайными числами.
|
||||||
Сначала сравниваем между собой корректность реализации алгоритмов — все полученные результаты
|
Сначала сравниваем между собой корректность реализации алгоритмов — все полученные результаты
|
||||||
|
|
|
@ -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. При
|
||||||
прочих равных условиях в настройках меняем количество процессоров. Запускаем вышеописанный
|
прочих равных условиях в настройках меняем количество процессоров. Запускаем вышеописанный
|
||||||
|
|
|
@ -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]`.
|
||||||
|
|
|
@ -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'
|
||||||
|
|
2
serve.sh
2
serve.sh
|
@ -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"
|
||||||
|
|
Loading…
Add table
Reference in a new issue