Compare commits
No commits in common. "0054f7245c4b55262f223515cbae7b4d4be6c985" and "6e77099ed2a7e10e83719283c0b0015edc345e08" have entirely different histories.
0054f7245c
...
6e77099ed2
16 changed files with 117 additions and 125 deletions
|
@ -3,6 +3,9 @@
|
|||
<pre>
|
||||
<a href='.'>.</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/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>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
© Головин Г.Г., 2021-2024
|
||||
© Головин Г.Г., 2021-2023
|
||||
|
||||
Опубликовано под [Открытой лицензией 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)
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
## Исходные тексты
|
||||
|
||||
- Используемые форматы — Markdown, Liquid, YAML.
|
||||
- Инструмент сборки — Jekyll и помидорные темы оформления.
|
||||
- Инструмент сборки — Jekyll с помидорными темами оформления.
|
||||
- Управление процессами — Bash скрипты.
|
||||
|
|
83
build.sh
83
build.sh
|
@ -1,34 +1,37 @@
|
|||
#!/bin/bash
|
||||
echo "Сборка сайта в двух помидорных темах и оптимизация результатов."
|
||||
time_ms="$(date '+%s%3N')"
|
||||
# удаление каталогов предыдущей сборки, если таковые имеются
|
||||
find . -maxdepth 1 -type d -name "_site*" -exec rm -rf {} \;
|
||||
# сборка сайта в двух помидорных темах
|
||||
function jekyll_build {
|
||||
case "$1" in
|
||||
"older") echo "Сборка старого помидора." ;;
|
||||
"color") echo "Сборка цветного помидора." ;;
|
||||
*) return ;; # две помидорные темы оформления
|
||||
esac
|
||||
mkdir -p "_site_$1"
|
||||
cp -r "jekyll_site/ru" "_site_$1"
|
||||
cp -r "jekyll_site/en" "_site_$1"
|
||||
cp -r "jekyll_site/ru/index.md" "_site_$1"
|
||||
cp -r "jekyll_site/_config_$1.yml" "_site_$1/_config.yml"
|
||||
cp -r "jekyll_site/Gemfile_$1" "_site_$1/Gemfile"
|
||||
cd "_site_$1" || return
|
||||
jekyll build --disable-disk-cache --quiet
|
||||
}
|
||||
export -f jekyll_build
|
||||
# запуск параллельной сборки сайта в двух помидорных темах оформления
|
||||
printf 'jekyll_build "%s"\0' {older,color} | xargs -n1 -0 -P0 bash -c
|
||||
# объединение двух сборок
|
||||
cp -r _site_older/_site .
|
||||
cp -r _site_color/_site ./_site/color
|
||||
# копирование без сборки
|
||||
milliseconds=$(date '+%s%3N')
|
||||
rm -rf _site
|
||||
rm -rf _site_older
|
||||
rm -rf _site_color
|
||||
echo "Сборка старого помидора."
|
||||
mkdir -p _site_older
|
||||
cp -r jekyll_site/_includes _site_older
|
||||
cp -r jekyll_site/ru _site_older
|
||||
cp -r jekyll_site/en _site_older
|
||||
cp -r jekyll_site/ru/index.md _site_older
|
||||
cp -r jekyll_site/_config_older.yml _site_older/_config.yml
|
||||
cp -r jekyll_site/Gemfile_older _site_older/Gemfile
|
||||
cd _site_older || exit
|
||||
jekyll build
|
||||
cp -r _site ..
|
||||
cd ..
|
||||
echo "Сборка цветного помидора."
|
||||
mkdir -p _site_color
|
||||
cp -r jekyll_site/_includes _site_color
|
||||
cp -r jekyll_site/ru _site_color
|
||||
cp -r jekyll_site/en _site_color
|
||||
cp -r jekyll_site/ru/index.md _site_color
|
||||
cp -r jekyll_site/_config_color.yml _site_color/_config.yml
|
||||
cp -r jekyll_site/Gemfile_color _site_color/Gemfile
|
||||
cd _site_color || exit
|
||||
jekyll build
|
||||
cp -r _site ../_site/color
|
||||
cd ..
|
||||
echo "Копирование без сборки."
|
||||
cp -r jekyll_site/img _site
|
||||
cp -r jekyll_site/robots.txt _site
|
||||
# оптимизация собранного контента
|
||||
echo "Оптимизация собранного контента."
|
||||
cd _site || exit
|
||||
cp -r assets/* .
|
||||
rm -r assets
|
||||
|
@ -36,19 +39,13 @@ rm -r color/assets/favicon.ico
|
|||
cp -r color/assets/* .
|
||||
rm -r color/assets
|
||||
rm -r color/404.html
|
||||
rm -r color/return.html
|
||||
# шаблоны для оптимизации ряда тегов
|
||||
expr+=('s|layout-padding=""|layout-padding|g')
|
||||
expr+=('s| class="language-plaintext highlighter-rouge"||g')
|
||||
expr+=('s| class="language-java highlighter-rouge"||g')
|
||||
expr+=('s|<div><div class="highlight">|<div class="highlight">|g')
|
||||
expr+=('s|</pre></div></div>|</pre></div>|g')
|
||||
expr+=('s|<hr />|<hr>|g')
|
||||
expr+=('s|<img(.+) />|<img\1>|g')
|
||||
# запуск параллельной обработки собранных страниц и оптимизация ряда тегов
|
||||
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)) мс."
|
||||
find . -type f -name '*.html' | sort -r | while read -r file; do
|
||||
sed -i 's/layout-padding=""/layout-padding/g' "$file"
|
||||
sed -i 's/ class="language-plaintext highlighter-rouge"//g' "$file"
|
||||
sed -i 's/ class="language-java highlighter-rouge"//g' "$file"
|
||||
sed -i 's/<div><div class="highlight"><pre class="highlight">/<div class="highlight"><pre class="highlight">/g' "$file"
|
||||
sed -i 's/<\/code><\/pre><\/div><\/div>/<\/code><\/pre><\/div>/g' "$file"
|
||||
sed -i 's/<hr \/>/<hr>/g' "$file"
|
||||
sed -i -r 's/<img(.+) \/>/<img\1>/g' "$file"
|
||||
done
|
||||
echo "Время выполнения сборки: $(("$(date '+%s%3N')" - "$milliseconds")) мс."
|
||||
|
|
|
@ -1,31 +1,18 @@
|
|||
# название сайта для подписи в футере
|
||||
# site parameters
|
||||
name: "Код с комментариями"
|
||||
# подпись в футере для переведённых страниц
|
||||
name_translated: "Code with comments"
|
||||
# URL адрес сайта, включая протокол
|
||||
url: "https://pomodoro3.mircloud.ru"
|
||||
# подпапка этой сборки для относительных URL-ов
|
||||
baseurl: "/color"
|
||||
# ссылка в верхнем левом углу заглавных страниц
|
||||
homepage_url: "https://gitea.com/pomodoro/3"
|
||||
# представление ссылки
|
||||
homepage_name: "GITEA"
|
||||
# подпапка альтернативной сборки
|
||||
homepage_url: "https://git.org.ru/pomodoro/3"
|
||||
homepage_name: "GIT.ORG.RU"
|
||||
older_tomato_baseurl: ""
|
||||
# часовой пояс для формата даты ISO-8601
|
||||
timezone: "Europe/Moscow"
|
||||
# имя автора для SEO-разметки и подписи в футере
|
||||
author: "Головин Г.Г."
|
||||
# транслитерация имени автора для переведённых страниц
|
||||
author_translated: "Golovin G.G."
|
||||
# дополнение к подписи в футере для переведённых страниц
|
||||
translation_caption: "translation from Russian"
|
||||
# номера счётчиков для страниц
|
||||
live_internet: "pomodoro"
|
||||
yandex_metrika: "95699483"
|
||||
# тема оформления для сборки
|
||||
# build parameters
|
||||
disable_disk_cache: true
|
||||
theme: color-tomato-theme
|
||||
# макет для сборки
|
||||
defaults:
|
||||
- scope:
|
||||
path: ""
|
||||
|
|
|
@ -1,31 +1,18 @@
|
|||
# название сайта для подписи в футере
|
||||
# site parameters
|
||||
name: "Код с комментариями"
|
||||
# подпись в футере для переведённых страниц
|
||||
name_translated: "Code with comments"
|
||||
# URL адрес сайта, включая протокол
|
||||
url: "https://pomodoro3.mircloud.ru"
|
||||
# подпапка этой сборки для относительных URL-ов
|
||||
baseurl: ""
|
||||
# ссылка в верхнем левом углу заглавных страниц
|
||||
homepage_url: "https://gitea.com/pomodoro/3"
|
||||
# представление ссылки
|
||||
homepage_name: "GITEA"
|
||||
# подпапка альтернативной сборки
|
||||
homepage_url: "https://git.org.ru/pomodoro/3"
|
||||
homepage_name: "GIT.ORG.RU"
|
||||
color_tomato_baseurl: "/color"
|
||||
# часовой пояс для формата даты ISO-8601
|
||||
timezone: "Europe/Moscow"
|
||||
# имя автора для SEO-разметки и подписи в футере
|
||||
author: "Головин Г.Г."
|
||||
# транслитерация имени автора для переведённых страниц
|
||||
author_translated: "Golovin G.G."
|
||||
# дополнение к подписи в футере для переведённых страниц
|
||||
translation_caption: "translation from Russian"
|
||||
# номера счётчиков для страниц
|
||||
live_internet: "pomodoro"
|
||||
yandex_metrika: "95699483"
|
||||
# тема оформления для сборки
|
||||
# build parameters
|
||||
disable_disk_cache: true
|
||||
theme: older-tomato-theme
|
||||
# макет для сборки
|
||||
defaults:
|
||||
- scope:
|
||||
path: ""
|
||||
|
|
2
jekyll_site/_includes/counters_body.html
Normal file
2
jekyll_site/_includes/counters_body.html
Normal 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 -->
|
16
jekyll_site/_includes/counters_head.html
Normal file
16
jekyll_site/_includes/counters_head.html
Normal 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>
|
|
@ -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 }}).*
|
||||
|
||||
{% 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*
|
||||
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
|
||||
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
|
||||
two matrices `M` and/or before the bypass of the rows of the first matrix `L`.
|
||||
|
@ -139,7 +139,7 @@ public static int[][] matrixMultiplicationNML(int l, int m, int n, int[][] a, in
|
|||
{% endcapture %}
|
||||
{%- include collapsed_block.html summary="Code without comments" content=collapsed_md -%}
|
||||
|
||||
{% 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
|
||||
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 }}).*
|
||||
|
||||
{% 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:
|
||||
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
|
||||
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.
|
||||
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
|
||||
```
|
||||
|
||||
{% 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
|
||||
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 }}).*
|
||||
|
||||
{% 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
|
||||
must be square, therefore if this is not the case, then first we supplement the matrices with zero
|
||||
|
@ -56,7 +56,7 @@ Blocks of the resulting matrix.
|
|||
{% include image_svg.html src="/img/sums3.svg" style="width:240pt; height:33pt;"
|
||||
alt="{\displaystyle{\begin{pmatrix}C_{11}&C_{12}\\C_{21}&C_{22}\end{pmatrix}}={\begin{pmatrix}P_{2}+P_{3}&T_{1}+P_{5}+P_{6}\\T_{2}-P_{7}&T_{2}+P_{5}\end{pmatrix}}.}" %}
|
||||
|
||||
{% 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
|
||||
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
|
||||
IntStream.range(0, 7).parallel().forEach(i -> {
|
||||
switch (i) { // recursive calls
|
||||
case 0 -> p[i] = multiplyMatrices(m, brd, s2, s6);
|
||||
case 1 -> p[i] = multiplyMatrices(m, brd, a11, b11);
|
||||
case 2 -> p[i] = multiplyMatrices(m, brd, a12, b21);
|
||||
case 3 -> p[i] = multiplyMatrices(m, brd, s3, s7);
|
||||
case 4 -> p[i] = multiplyMatrices(m, brd, s1, s5);
|
||||
case 5 -> p[i] = multiplyMatrices(m, brd, s4, b22);
|
||||
case 6 -> p[i] = multiplyMatrices(m, brd, a22, s8);
|
||||
case 0: p[i] = multiplyMatrices(m, brd, s2, s6); break;
|
||||
case 1: p[i] = multiplyMatrices(m, brd, a11, b11); break;
|
||||
case 2: p[i] = multiplyMatrices(m, brd, a12, b21); break;
|
||||
case 3: p[i] = multiplyMatrices(m, brd, s3, s7); break;
|
||||
case 4: p[i] = multiplyMatrices(m, brd, s1, s5); break;
|
||||
case 5: p[i] = multiplyMatrices(m, brd, s4, b22); break;
|
||||
case 6: p[i] = multiplyMatrices(m, brd, a22, s8); break;
|
||||
}
|
||||
});
|
||||
// summation of blocks
|
||||
|
@ -169,7 +169,7 @@ private static int[][] putQuadrants(int m, int n,
|
|||
{% endcapture %}
|
||||
{%- 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
|
||||
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.
|
||||
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
|
||||
```
|
||||
|
||||
{% 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
|
||||
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 }}).*
|
||||
|
||||
{% include heading.html text="Построчный алгоритм" hash="row-wise-algorithm" %}
|
||||
## Построчный алгоритм {#row-wise-algorithm}
|
||||
|
||||
Внешний цикл обходит строки первой матрицы `L`, далее идёт цикл по *общей стороне* двух матриц `M`
|
||||
и за ним цикл по колонкам второй матрицы `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`, далее идёт цикл по строкам первой матрицы
|
||||
`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`
|
||||
и/или перед обходом строк первой матрицы `L`.
|
||||
|
@ -137,7 +137,7 @@ public static int[][] matrixMultiplicationNML(int l, int m, int n, int[][] a, in
|
|||
{% endcapture %}
|
||||
{%- include collapsed_block.html summary="Код без комментариев" content=collapsed_md -%}
|
||||
|
||||
{% include heading.html text="Сравнение алгоритмов" hash="comparing-algorithms" %}
|
||||
## Сравнение алгоритмов {#comparing-algorithms}
|
||||
|
||||
Для проверки возьмём две матрицы `A=[500×700]` и `B=[700×450]`, заполненные случайными числами.
|
||||
Сначала сравниваем между собой корректность реализации алгоритмов — все полученные результаты
|
||||
|
|
|
@ -19,7 +19,7 @@ date: 2022.02.08
|
|||
|
||||
*Дальнейшая оптимизация: [Алгоритм Винограда — Штрассена]({{ '/ru/2022/02/10/winograd-strassen-algorithm.html' | relative_url }}).*
|
||||
|
||||
{% include heading.html text="Параллельный поток" hash="parallel-stream" %}
|
||||
## Параллельный поток {#parallel-stream}
|
||||
|
||||
Строки первой матрицы `L` обходим в параллельном режиме. Внутри каждого потока два вложенных цикла:
|
||||
по *общей стороне* двух матриц `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`
|
||||
|
@ -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]`, заполненные случайными числами.
|
||||
Сначала сравниваем между собой корректность реализации двух алгоритмов — произведения матриц
|
||||
|
@ -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
|
||||
```
|
||||
|
||||
{% include heading.html text="Сравнение алгоритмов" hash="comparing-algorithms" %}
|
||||
## Сравнение алгоритмов {#comparing-algorithms}
|
||||
|
||||
На восьмиядерном компьютере Linux x64 создаём для тестов виртуальную машину Windows x64. При
|
||||
прочих равных условиях в настройках меняем количество процессоров. Запускаем вышеописанный
|
||||
|
|
|
@ -24,7 +24,7 @@ date: 2022.02.10
|
|||
|
||||
*Алгоритм на трёх вложенных циклах: [Оптимизация умножения матриц]({{ '/ru/2021/12/09/optimizing-matrix-multiplication.html' | relative_url }}).*
|
||||
|
||||
{% include heading.html text="Описание алгоритма" hash="algorithm-description" %}
|
||||
## Описание алгоритма {#algorithm-description}
|
||||
|
||||
Матрицы должны быть одинакового размера. Разделяем каждую матрицу на 4 равных блока. Блоки должны быть
|
||||
квадратными, поэтому если это не так, тогда сначала дополняем матрицы нулевыми строками и столбцами,
|
||||
|
@ -53,7 +53,7 @@ alt="{\displaystyle{\begin{aligned}T_{1}&=P_{1}+P_{2};\\T_{2}&=T_{1}+P_{4}.\end{
|
|||
{% include image_svg.html src="/img/sums3.svg" style="width:240pt; height:33pt;"
|
||||
alt="{\displaystyle{\begin{pmatrix}C_{11}&C_{12}\\C_{21}&C_{22}\end{pmatrix}}={\begin{pmatrix}P_{2}+P_{3}&T_{1}+P_{5}+P_{6}\\T_{2}-P_{7}&T_{2}+P_{5}\end{pmatrix}}.}" %}
|
||||
|
||||
{% include heading.html text="Гибридный алгоритм" hash="hybrid-algorithm" %}
|
||||
## Гибридный алгоритм {#hybrid-algorithm}
|
||||
|
||||
Каждую матрицу `A` и `B` делим на 4 *равных* блока, при необходимости дополняем недостающие части
|
||||
нулями. Выполняем 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 -> {
|
||||
switch (i) { // рекурсивные вызовы
|
||||
case 0 -> p[i] = multiplyMatrices(m, brd, s2, s6);
|
||||
case 1 -> p[i] = multiplyMatrices(m, brd, a11, b11);
|
||||
case 2 -> p[i] = multiplyMatrices(m, brd, a12, b21);
|
||||
case 3 -> p[i] = multiplyMatrices(m, brd, s3, s7);
|
||||
case 4 -> p[i] = multiplyMatrices(m, brd, s1, s5);
|
||||
case 5 -> p[i] = multiplyMatrices(m, brd, s4, b22);
|
||||
case 6 -> p[i] = multiplyMatrices(m, brd, a22, s8);
|
||||
case 0: p[i] = multiplyMatrices(m, brd, s2, s6); break;
|
||||
case 1: p[i] = multiplyMatrices(m, brd, a11, b11); break;
|
||||
case 2: p[i] = multiplyMatrices(m, brd, a12, b21); break;
|
||||
case 3: p[i] = multiplyMatrices(m, brd, s3, s7); break;
|
||||
case 4: p[i] = multiplyMatrices(m, brd, s1, s5); break;
|
||||
case 5: p[i] = multiplyMatrices(m, brd, s4, b22); break;
|
||||
case 6: p[i] = multiplyMatrices(m, brd, a22, s8); break;
|
||||
}
|
||||
});
|
||||
// суммируем блоки
|
||||
|
@ -165,7 +165,7 @@ private static int[][] putQuadrants(int m, int n,
|
|||
{% endcapture %}
|
||||
{%- 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]`, заполненные случайными
|
||||
числами. Минимальный размер блока возьмём `[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
|
||||
```
|
||||
|
||||
{% include heading.html text="Сравнение алгоритмов" hash="comparing-algorithms" %}
|
||||
## Сравнение алгоритмов {#comparing-algorithms}
|
||||
|
||||
На восьмиядерном компьютере Linux x64 запускаем вышеописанный тест 100 раз вместо 10. Минимальный
|
||||
размер блока берём `[brd=200]`. Изменяем только `n` — размеры обеих матриц `A=[n×n]` и `B=[n×n]`.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
echo "Создание архива для последующего развёртывания."
|
||||
echo "Подготовка архива для последующего развёртывания."
|
||||
cd _site || exit
|
||||
rm -rf ../pomodoro3.zip
|
||||
7z a ../pomodoro3.zip . | grep -E '\S'
|
||||
7z a ../pomodoro3.zip ./*
|
||||
|
|
2
serve.sh
2
serve.sh
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
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"
|
||||
|
|
Loading…
Add table
Reference in a new issue