2023-06-30

This commit is contained in:
Gennadiy 2023-12-17 07:55:45 +03:00
parent fdcd2e4591
commit 8ed24b365e
30 changed files with 2154 additions and 0 deletions

2
.gitattributes vendored
View file

@ -0,0 +1,2 @@
jekyll_site/ru/** linguist-language=Java
jekyll_site/en/** linguist-language=Java

3
.gitignore vendored
View file

@ -1,2 +1,5 @@
.idea .idea
*.iml *.iml
*.zip
_site*
.repo_*.sh

57
DIRECTORY-TREE.md Normal file
View file

@ -0,0 +1,57 @@
## Дерево каталогов
<pre>
.
├─ <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/09'>09</a>
│ │ │ │ ├─ <a href='jekyll_site/en/2021/09/07'>07</a>
│ │ │ │ │ └─ <a href='jekyll_site/en/2021/09/07/cartesian-product-of-sets.md'>cartesian-product-of-sets.md</a>
│ │ │ │ ├─ <a href='jekyll_site/en/2021/09/10'>10</a>
│ │ │ │ │ └─ <a href='jekyll_site/en/2021/09/10/pascals-triangle-in-java.md'>pascals-triangle-in-java.md</a>
│ │ │ │ ├─ <a href='jekyll_site/en/2021/09/14'>14</a>
│ │ │ │ │ └─ <a href='jekyll_site/en/2021/09/14/combinations-by-columns.md'>combinations-by-columns.md</a>
│ │ │ │ └─ <a href='jekyll_site/en/2021/09/22'>22</a>
│ │ │ │ └─ <a href='jekyll_site/en/2021/09/22/combinations-of-sequence-elements.md'>combinations-of-sequence-elements.md</a>
│ │ │ └─ <a href='jekyll_site/en/2021/10'>10</a>
│ │ │ └─ <a href='jekyll_site/en/2021/10/05'>05</a>
│ │ │ └─ <a href='jekyll_site/en/2021/10/05/cartesian-product-parallel-streams.md'>cartesian-product-parallel-streams.md</a>
│ │ └─ <a href='jekyll_site/en/index.md'>index.md</a>
│ ├─ <a href='jekyll_site/img'>img</a>
│ │ ├─ <a href='jekyll_site/img/arrangement-formula.svg'>arrangement-formula.svg</a>
│ │ ├─ <a href='jekyll_site/img/arrangements-quantity.gif'>arrangements-quantity.gif</a>
│ │ └─ <a href='jekyll_site/img/three-elements-sequence.svg'>three-elements-sequence.svg</a>
│ ├─ <a href='jekyll_site/ru'>ru</a>
│ │ ├─ <a href='jekyll_site/ru/2021'>2021</a>
│ │ │ ├─ <a href='jekyll_site/ru/2021/09'>09</a>
│ │ │ │ ├─ <a href='jekyll_site/ru/2021/09/06'>06</a>
│ │ │ │ │ └─ <a href='jekyll_site/ru/2021/09/06/cartesian-product-of-sets.md'>cartesian-product-of-sets.md</a>
│ │ │ │ ├─ <a href='jekyll_site/ru/2021/09/09'>09</a>
│ │ │ │ │ └─ <a href='jekyll_site/ru/2021/09/09/pascals-triangle-in-java.md'>pascals-triangle-in-java.md</a>
│ │ │ │ ├─ <a href='jekyll_site/ru/2021/09/13'>13</a>
│ │ │ │ │ └─ <a href='jekyll_site/ru/2021/09/13/combinations-by-columns.md'>combinations-by-columns.md</a>
│ │ │ │ └─ <a href='jekyll_site/ru/2021/09/20'>20</a>
│ │ │ │ └─ <a href='jekyll_site/ru/2021/09/20/combinations-of-sequence-elements.md'>combinations-of-sequence-elements.md</a>
│ │ │ └─ <a href='jekyll_site/ru/2021/10'>10</a>
│ │ │ └─ <a href='jekyll_site/ru/2021/10/04'>04</a>
│ │ │ └─ <a href='jekyll_site/ru/2021/10/04/cartesian-product-parallel-streams.md'>cartesian-product-parallel-streams.md</a>
│ │ └─ <a href='jekyll_site/ru/index.md'>index.md</a>
│ ├─ <a href='jekyll_site/Gemfile_color'>Gemfile_color</a>
│ ├─ <a href='jekyll_site/Gemfile_older'>Gemfile_older</a>
│ ├─ <a href='jekyll_site/_config_color.yml'>_config_color.yml</a>
│ ├─ <a href='jekyll_site/_config_older.yml'>_config_older.yml</a>
│ └─ <a href='jekyll_site/robots.txt'>robots.txt</a>
├─ <a href='CONTRIBUTING.md'>CONTRIBUTING.md</a>
├─ <a href='DIRECTORY-TREE.md'>DIRECTORY-TREE.md</a>
├─ <a href='LICENSE.md'>LICENSE.md</a>
├─ <a href='OPEN_LICENSE.txt'>OPEN_LICENSE.txt</a>
├─ <a href='README.en.md'>README.en.md</a>
├─ <a href='README.md'>README.md</a>
├─ <a href='build.sh'>build.sh</a>
├─ <a href='package.sh'>package.sh</a>
└─ <a href='serve.sh'>serve.sh</a>
</pre>

17
README.en.md Normal file
View file

@ -0,0 +1,17 @@
## Website pages
- [Cartesian product in parallel streams](https://pomodoro2.mircloud.ru/en/2021/10/05/cartesian-product-parallel-streams.html) — 05.10.2021.
- [Combinations of sequence elements](https://pomodoro2.mircloud.ru/en/2021/09/22/combinations-of-sequence-elements.html) — 22.09.2021.
- [Combinations of elements by columns](https://pomodoro2.mircloud.ru/en/2021/09/14/combinations-by-columns.html) — 14.09.2021.
- [Pascal's Triangle in Java](https://pomodoro2.mircloud.ru/en/2021/09/10/pascals-triangle-in-java.html) — 10.09.2021.
- [Cartesian product of sets](https://pomodoro2.mircloud.ru/en/2021/09/07/cartesian-product-of-sets.html) — 07.09.2021.
## [Source texts](README.md)
- Series of the static websites [«Pomodori»](https://hub.mos.ru/golovin.gg/pomodoro/blob/master/README.en.md).
- Used formats — Markdown, Liquid, YAML.
- Build tool — Jekyll with tomato design themes.
- Automation of processes — Bash scripts for command line.
- [build.sh](build.sh) — Building a site in two tomato themes and optimizing the results.
- [serve.sh](serve.sh) — Local deployment to verify the correctness of the build.
- [package.sh](package.sh) — Preparing an archive for subsequent deployment.

17
README.md Normal file
View file

@ -0,0 +1,17 @@
## Страницы вёб-сайта
- [Декартово произведение в параллельных потоках](https://pomodoro2.mircloud.ru/ru/2021/10/04/cartesian-product-parallel-streams.html) — 04.10.2021.
- [Комбинации элементов последовательности](https://pomodoro2.mircloud.ru/ru/2021/09/20/combinations-of-sequence-elements.html) — 20.09.2021.
- [Комбинации элементов по столбцам](https://pomodoro2.mircloud.ru/ru/2021/09/13/combinations-by-columns.html) — 13.09.2021.
- [Треугольник Паскаля на Java](https://pomodoro2.mircloud.ru/ru/2021/09/09/pascals-triangle-in-java.html) — 09.09.2021.
- [Декартово произведение множеств](https://pomodoro2.mircloud.ru/ru/2021/09/06/cartesian-product-of-sets.html) — 06.09.2021.
## [Исходные тексты](README.en.md)
- Серия статических вёб-сайтов [«Помидоры»](https://hub.mos.ru/golovin.gg/pomodoro/blob/master/README.md).
- Используемые форматы — Markdown, Liquid, YAML.
- Инструмент сборки — Jekyll с помидорными темами оформления.
- Автоматизация процессов — Bash скрипты для командной строки.
- [build.sh](build.sh) — Сборка сайта в двух помидорных темах и оптимизация результатов.
- [serve.sh](serve.sh) — Локальное развёртывание для проверки корректности сборки.
- [package.sh](package.sh) — Подготовка архива для последующего развёртывания.

51
build.sh Executable file
View file

@ -0,0 +1,51 @@
#!/bin/bash
echo "Сборка сайта в двух помидорных темах и оптимизация результатов."
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
rm -r color/assets/favicon.ico
cp -r color/assets/* .
rm -r color/assets
rm -r color/404.html
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")) мс."

View file

@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "jekyll"
gem "color-tomato-theme"

View file

@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "jekyll"
gem "older-tomato-theme"

View file

@ -0,0 +1,20 @@
# site parameters
name: "Код с комментариями"
name_translated: "Code with comments"
url: "https://pomodoro2.mircloud.ru"
baseurl: "/color"
homepage_url: "https://git.org.ru/pomodoro/2"
homepage_name: "GIT.ORG.RU"
older_tomato_baseurl: ""
timezone: "Europe/Moscow"
author: "Головин Г.Г."
author_translated: "Golovin G.G."
translation_caption: "translation from Russian"
# build parameters
disable_disk_cache: true
theme: color-tomato-theme
defaults:
- scope:
path: ""
values:
layout: default

View file

@ -0,0 +1,20 @@
# site parameters
name: "Код с комментариями"
name_translated: "Code with comments"
url: "https://pomodoro2.mircloud.ru"
baseurl: ""
homepage_url: "https://git.org.ru/pomodoro/2"
homepage_name: "GIT.ORG.RU"
color_tomato_baseurl: "/color"
timezone: "Europe/Moscow"
author: "Головин Г.Г."
author_translated: "Golovin G.G."
translation_caption: "translation from Russian"
# build parameters
disable_disk_cache: true
theme: older-tomato-theme
defaults:
- scope:
path: ""
values:
layout: default

View file

@ -0,0 +1,2 @@
<noscript><div><img src="https://mc.yandex.ru/watch/85876478" 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=UA-209134013-2"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-209134013-2');
</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(85876478,"init",{clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true});
</script>

View file

@ -0,0 +1,213 @@
---
title: Cartesian product of sets
description: Consider an algorithm for obtaining a Cartesian product of multiple sets using three nested loops. The number of sets and their elements can be arbitrary.
sections: [Combinatorics,Direct product]
tags: [java,combinatorics,algorithms,cartesian product,combinations,set,list,array,loops,nested loops]
canonical_url: /en/2021/09/07/cartesian-product-of-sets.html
url_translated: /ru/2021/09/06/cartesian-product-of-sets.html
title_translated: Декартово произведение множеств
date: 2021.09.07
lang: en
---
Consider an algorithm for obtaining a *Cartesian product* of multiple sets using three nested
loops. The number of sets and their elements can be arbitrary. We multiply the sets sequentially
and accumulate the result. The order does not matter, since the product does not change due to the
permutation of the multipliers. As a result, the order will be different, but the combinations will
be the same.
For clarity, let's take several *ordered* sets:
```
a = [A,B,C,D]
b = [E,F,G]
c = [H,I]
d = [J]
```
The number of possible combinations is the product of the number of elements of all sets:
```
4 * 3 * 2 * 1 = 24
```
Let's write a method in Java to solve such issues, we will use three nested `for` loops.
First, we prepare a *list of lists* `List<List<T>>`, filled with one empty value.
We will use it as an intermediate result and as a final result.
Then we pass through the received lists and sequentially supplement the intermediate
result with their elements. At each step, we get a new intermediate result and move on.
Thus, we consistently multiply pairs of lists and step-by-step accumulate the result.
Schematically, this process looks like this:
```
result0: [[]]
list1: [A,B,C,D]
--------
result1: [[A],[B],[C],[D]]
list2: [E,F,G]
--------
result2: [[A,E],[A,F],[A,G],[B,E],[B,F],...[D,G]]
list3: [H,I]
--------
result3: [[A,E,H],[A,E,I],[A,F,H],[A,F,I],[A,G,H],...[D,G,I]]
list4: [J]
--------
result4: [[A,E,H,J],[A,E,I,J],[A,F,H,J],[A,F,I,J],[A,G,H,J],...[D,G,I,J]]
```
### Combinations by columns {#combinations-by-columns}
```
Number of combinations: 24
[A, E, H, J] [B, E, H, J] [C, E, H, J] [D, E, H, J]
[A, E, I, J] [B, E, I, J] [C, E, I, J] [D, E, I, J]
[A, F, H, J] [B, F, H, J] [C, F, H, J] [D, F, H, J]
[A, F, I, J] [B, F, I, J] [C, F, I, J] [D, F, I, J]
[A, G, H, J] [B, G, H, J] [C, G, H, J] [D, G, H, J]
[A, G, I, J] [B, G, I, J] [C, G, I, J] [D, G, I, J]
```
## Cartesian product of lists {#cartesian-product-of-lists}
The list can contain a *modifiable number* of elements. This simplifies the code.
```java
/**
* @param lists an arbitrary number of lists
* @param <T> the type of elements in lists
* @return the Cartesian product of the passed lists
*/
public static <T> List<List<T>> cartesianProduct(List<List<T>> lists) {
// incoming data is not null
if (lists == null) return Collections.emptyList();
// intermediate result, contains one empty value
List<List<T>> cp = Collections.singletonList(Collections.<T>emptyList());
// pass through the received lists
for (List<T> list : lists) {
// non-null and non-empty lists
if (list == null || list.size() == 0) continue;
// next intermediate result
List<List<T>> next = new ArrayList<>();
// rows of the current intermediate result
for (List<T> row : cp) {
// elements of the current list
for (T el : list) {
// a new row for the next intermediate
// result, copy of the current row
List<T> nRow = new ArrayList<>(row);
// add the current element
nRow.add(el);
// add to the next intermediate result
next.add(nRow);
}
}
// update the intermediate result
cp = next;
}
// the final result
return cp;
}
```
```java
// start the program and output the result
public static void main(String[] args) {
// an arbitrary number of lists and their elements
List<String> a = Arrays.asList("A", "B", "C", "D");
List<String> b = Arrays.asList("E", "F", "G");
List<String> c = Arrays.asList("H", "I");
List<String> d = Arrays.asList("J");
// cartesian product
List<List<String>> cp = cartesianProduct(Arrays.asList(a, b, c, d));
// output
System.out.println("Number of combinations: " + cp.size());
// combinations by columns
int rows = 6;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cp.size(); j++)
if (j % rows == i)
System.out.print(" " + cp.get(j));
System.out.println();
}
}
```
The output for this and the following code is the same, see above: [combinations by columns](#combinations-by-columns).
## Cartesian product of arrays {#cartesian-product-of-arrays}
The array contains a *fixed number* of elements. The code looks a little more complicated.
```java
/**
* @param arrays an arbitrary number of arrays
* @param clazz the class of elements in arrays
* @param <T> the type of elements in arrays
* @return the Cartesian product of the passed arrays
*/
@SuppressWarnings("unchecked")
public static <T> T[][] cartesianProduct(Class<T> clazz, T[]... arrays) {
// incoming data is not null
if (clazz == null || arrays == null)
return (T[][]) Array.newInstance(clazz, 0, 0);
// intermediate result, contains one empty value
T[][] cp = (T[][]) Array.newInstance(clazz, 1, 0);
// pass through the received arrays
for (int a = 0; a < arrays.length; a++) {
// current array
T[] arr = arrays[a];
// non-null and non-empty array
if (arr == null || arr.length == 0) continue;
// next intermediate result, specify the number of rows
T[][] next = (T[][]) Array.newInstance(clazz,cp.length*arr.length,0);
// rows of the current intermediate result
for (int r = 0; r < cp.length; r++) {
// current row
T[] row = cp[r];
// elements of the current array
for (int e = 0; e < arr.length; e++) {
// current element
T el = arr[e];
// copy the current row into the new array [length + 1]
T[] nRow = Arrays.copyOf(row, row.length + 1);
// add the current element
nRow[row.length] = el;
// add to the next intermediate result
next[r * arr.length + e] = nRow;
}
}
// update the intermediate result
cp = next;
}
// the final result
return cp;
}
```
```java
// start the program and output the result
public static void main(String[] args) {
// an arbitrary number of arrays and their elements
String[] a = {"A", "B", "C", "D"};
String[] b = {"E", "F", "G"};
String[] c = {"H", "I"};
String[] d = {"J"};
// cartesian product
String[][] cp = cartesianProduct(String.class, a, b, c, d);
// output
System.out.println("Number of combinations: " + cp.length);
// combinations by columns
int rows = 6;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cp.length; j++)
if (j % rows == i)
System.out.print(" " + Arrays.toString(cp[j]));
System.out.println();
}
}
```
The output for this and the previous code is the same, see above: [combinations by columns](#combinations-by-columns).

View file

@ -0,0 +1,72 @@
---
title: Pascal's Triangle in Java
description: Consider a variant of the implementation of Pascal's triangle in Java. For the simplicity of storing and processing data, we represent the triangle as...
sections: [Two-dimensional array,Binomial coefficients]
tags: [java,algorithms,array,two-dimensional array,loops,nested loops]
canonical_url: /en/2021/09/10/pascals-triangle-in-java.html
url_translated: /ru/2021/09/09/pascals-triangle-in-java.html
title_translated: Треугольник Паскаля на Java
date: 2021.09.10
lang: en
---
Consider a variant of the implementation of *Pascal's triangle* in Java. For the simplicity
of storing and processing data, we represent the triangle as a two-dimensional array, in which
the elements of the first row and column are equal to one, and all other elements are the sum
of the two previous elements in the row and column.
```
A[i][j] = A[i][j-1] + A[i-1][j];
```
For example, if {`n = 8`} then the array will look like this:
```
1 1 1 1 1 1 1 1
1 2 3 4 5 6 7
1 3 6 10 15 21
1 4 10 20 35
1 5 15 35
1 6 21
1 7
1
```
Create and fill a two-dimensional array with decreasing row length:
```java
int n = 8;
// array of 'n' rows
int[][] arr = new int[n][];
// iterate through the rows of the array
for (int i = 0; i < n; i++) {
// row of 'n-i' elements
arr[i] = new int[n - i];
// iterate through the elements of the row
for (int j = 0; j < n - i; j++) {
if (i == 0 || j == 0) {
// elements of the first row
// and column are equal to one
arr[i][j] = 1;
} else {
// all other elements are the sum of the two
// previous elements in the row and column
arr[i][j] = arr[i][j - 1] + arr[i - 1][j];
}
}
}
```
Output the array row-wise:
```java
// iterate through the array rows
for (int[] row : arr) {
// iterate through the row elements
for (int el : row)
// space and two-digit number
System.out.printf(" %2d", el);
// line separator
System.out.println();
}
```

View file

@ -0,0 +1,155 @@
---
title: Combinations of elements by columns
description: In a two-dimensional array, data is stored row-wise. Consider an algorithm for obtaining a Cartesian product by columns using three nested loops. The...
sections: [Combinatorics,Direct product]
tags: [java,combinatorics,algorithms,cartesian product,combinations,columns,set,list,array,loops,nested loops]
canonical_url: /en/2021/09/14/combinations-by-columns.html
url_translated: /ru/2021/09/13/combinations-by-columns.html
title_translated: Комбинации элементов по столбцам
date: 2021.09.14
lang: en
---
In a two-dimensional array, data is stored row-wise. Consider an algorithm for obtaining
a *Cartesian product* by columns using three nested loops. The number of rows and columns
of the table can be arbitrary. We multiply the columns sequentially and accumulate the
result. The values do not necessarily have to be populated we discard the null elements.
For example, let's take a partially filled *jagged two-dimensional array*:
```java
| col1 | col2 | col3 | col4
-----|------|------|------|------
row1 | "A1" | "B1" | "C1" | "D1"
row2 | "A2" | "B2" | null | "D2"
row3 | "A3" | null | null | "D3"
row4 | "A4" | null |
```
The number of possible combinations is the product of the number of elements of all columns:
```
4 * 2 * 1 * 3 = 24
```
Let's write a method in Java to solve such issues, we will use three nested `for` loops.
First, we prepare a *list of lists* `List<List<T>>`, filled with one empty value. We will
use it as an intermediate result and as a final result.
Then we pass through the table columns, while they are present, we consider the last
column is the one after which all the elements are null. At each step, we supplement the
intermediate result with the elements of the current column and get a new intermediate
result. Thus, we consistently multiply columns and step-by-step accumulate the result.
Schematically, this process looks like this:
```
res0 * col1 = res1 * col2 = res2 * col3 = res3 * col4 = res4
-----|------|------|------|-------|------|----------|------|------------
[] * A1 = A1 * B1 = A1,B1 * C1 = A1,B1,C1 * D1 = A1,B1,C1,D1
* A2 = A2 * B2 = A1,B2 * = A1,B2,C1 * D2 = A1,B1,C1,D2
* A3 = A3 * = A2,B1 * = A2,B1,C1 * D3 = A1,B1,C1,D3
* A4 = A4 * = A2,B2 * = A2,B2,C1 * = A1,B2,C1,D1
* = * = A3,B1 * = A3,B1,C1 * = A1,B2,C1,D2
* = * = A3,B2 * = A3,B2,C1 * = A1,B2,C1,D3
* = * = A4,B1 * = A4,B1,C1 * = A2,B1,C1,D1
* = * = A4,B2 * = A4,B2,C1 * = A2,B1,C1,D2
* = * = * = * = A2,B1,C1,D3
* = * = * = * = A2,B2,C1,D1
* = * = * = * = ...........
* = * = * = * = ...........
* = * = * = * = A4,B2,C1,D3
-----|------|------|------|-------|------|----------|------|------------
1 * 4 = 4 * 2 = 8 * 1 = 8 * 3 = 24
```
### Combinations by columns {#combinations-by-columns}
```
Number of combinations: 24
[A1, B1, C1, D1] [A2, B1, C1, D1] [A3, B1, C1, D1] [A4, B1, C1, D1]
[A1, B1, C1, D2] [A2, B1, C1, D2] [A3, B1, C1, D2] [A4, B1, C1, D2]
[A1, B1, C1, D3] [A2, B1, C1, D3] [A3, B1, C1, D3] [A4, B1, C1, D3]
[A1, B2, C1, D1] [A2, B2, C1, D1] [A3, B2, C1, D1] [A4, B2, C1, D1]
[A1, B2, C1, D2] [A2, B2, C1, D2] [A3, B2, C1, D2] [A4, B2, C1, D2]
[A1, B2, C1, D3] [A2, B2, C1, D3] [A3, B2, C1, D3] [A4, B2, C1, D3]
```
## Cartesian product by columns {#cartesian-product-by-columns}
The code will look simpler if you first *transpose* an array of arrays, but if
this cannot be done, then in the outer loop, pass through the table columns as
long as they are still exist.
```java
/**
* @param table the two-dimensional list
* @param <T> the type of elements in list
* @return the Cartesian product of the elements by columns
*/
public static <T> List<List<T>> cartesianProduct(List<List<T>> table) {
// incoming data is not null
if (table == null) return Collections.emptyList();
// intermediate result, contains one empty value
List<List<T>> cp = Collections.singletonList(Collections.<T>emptyList());
// columns are still present
boolean notLast = true;
// pass through the table columns, while they are present
for (int i = 0; notLast; i++) {
// there are no more columns
notLast = false;
// next intermediate result
List<List<T>> next = new ArrayList<>();
// pass through the combinations of the current intermediate result
for (List<T> comb : cp) {
// pass through the rows of the table
for (List<T> row : table) {
// if the column is still present and its value is also present
if (row != null && i < row.size() && row.get(i) != null) {
// a new combination, copy the current combination
List<T> nComb = new ArrayList<>(comb);
// add the value from the column
nComb.add(row.get(i));
// add to the next intermediate result
next.add(nComb);
// columns are still present
notLast = true;
}
}
}
// if the columns are still present, then we update the intermediate
// result and go to the next iteration, otherwise we exit the loop
if (notLast) cp = next;
}
// the final result
return cp;
}
```
```java
// start the program and output the result
public static void main(String[] args) {
// an arbitrary number of rows and their elements
List<String> row1 = Arrays.asList("A1", "B1", "C1", "D1");
List<String> row2 = Arrays.asList("A2", "B2", null, "D2");
List<String> row3 = Arrays.asList("A3", null, null, "D3");
List<String> row4 = Arrays.asList("A4", null);
// jagged two-dimensional list
List<List<String>> table = Arrays.asList(row1, row2, row3, row4);
// cartesian product
List<List<String>> cp = cartesianProduct(table);
// output
System.out.println("Number of combinations: " + cp.size());
// combinations by columns
int rows = 6;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cp.size(); j++)
if (j % rows == i)
System.out.print(" " + cp.get(j));
System.out.println();
}
}
```
The output for this code see above: [combinations by columns](#combinations-by-columns).

View file

@ -0,0 +1,240 @@
---
title: Combinations of sequence elements
description: Consider a problem where you need to get all possible combinations of sequence elements, in which the number of elements in the combination does not exceed...
sections: [Combinatorics,Arrangements,Permutations]
tags: [java,combinatorics,algorithms,arrangement,permutation,combinations,sequence,set,list,loops,nested loops]
canonical_url: /en/2021/09/22/combinations-of-sequence-elements.html
url_translated: /ru/2021/09/20/combinations-of-sequence-elements.html
title_translated: Комбинации элементов последовательности
date: 2021.09.22
lang: en
---
Consider a problem where you need to get all possible combinations of sequence elements, in which
the number of elements in the combination does not exceed a given maximum, and let's write a method
in Java with the appropriate filter for the minimum and maximum number of elements.
*[Table setting problem](#table-setting-problem) [Method for solving in Java](#combinations-of-length)*
An *arrangement* is an ordered set of {`k`} distinct elements from a set of distinct {`n`} elements,
where {<code>k&nbsp;&le;&nbsp;n</code>}. If {<code>k&nbsp;=&nbsp;n</code>}, then this ordered set
is a *permutation*. For the universality of the solution, we'll also consider *permutations* as
a special case of *arrangement*.
## Number of possible combinations {#number-of-possible-combinations}
For clarity, we'll take a sequence of three elements {`XYZ`}, draw all possible subsets
of this set, add permutations to them and calculate the number of combinations.
{% include picture.html src="/img/arrangements-quantity.gif" size100=true background=true
alt="We get the number of all possible arrangements of the sequence elements"
caption="We get the number of all possible arrangements of the sequence elements" %}
Formula for the number of arrangements:
{% include image_svg.html src="/img/arrangement-formula.svg" style="width: 83pt; height: 46pt;"
alt="\sum_{k=0}^{n} {n! \over (n-k)!}" %}
Sequence of three elements:
{% include image_svg.html src="/img/three-elements-sequence.svg" style="width: 375pt; height: 48pt;"
alt="\sum_{k=0}^{3} {3! \over (3-k)!} = {3! \over 3!} + {3! \over 2!} + {3! \over 1!} + {3! \over 0!} = 1+3+6+6 = 16." %}
Implementation in Java:
```java
public static void main(String[] args) {
// number of sequence elements
int n = 3;
// number of possible combinations
int sum = 0;
// bypass the possible numbers of elements
for (int k = 0; k <= n; k++)
// add up the numbers of arrangements
sum += factorial(n) / factorial(n - k);
// output
System.out.println(sum); // 16
}
// factorial of a number
static int factorial(int n) {
int fact = 1;
for (int i = 2; i <= n; i++)
fact *= i;
return fact;
}
```
## Combinations of three elements {#combinations-of-elements}
Let's compare two sequences of three elements: digits {`123`} and letters {`XYZ`}.
The type of elements is different combinations are the same, because the sequence
numbers of the elements are the same.
```
number of variants: 16
[][1][2][3][12][13][21][23][31][32][123][132][213][231][312][321]
[][X][Y][Z][XY][XZ][YX][YZ][ZX][ZY][XYZ][XZY][YXZ][YZX][ZXY][ZYX]
```
Let's compare sequences of [`1..12`] elements: the number of variants grows rapidly and
soon goes beyond the `Integer`, then for {<code>n&nbsp;&gt;&nbsp;12</code>} you will need
to use `Long`, and when {<code>n&nbsp;&gt;&nbsp;20</code>} already `BigInteger`.
```
n number of variants
1 2
2 5
3 16
4 65
5 326
6 1957
7 13700
8 109601
9 986410
10 9864101
11 108505112
12 1302061345
```
Consider a problem where you need to limit the possible variants
by the maximum number of elements contained in them.
## Table setting problem {#table-setting-problem}
Four guests are invited to dinner {<code>n&nbsp;=&nbsp;4</code>}, of whom it is known
that no more than two people will arrive {<code>k&nbsp;=&nbsp;2</code>}, and the order
of their appearance is important, since the table setting depends on it. It is also
known that when the first one arrives, this person will say who will be the second and
whether this person will arrive. Calculate the possible variants for table setting.
### Solution approach {#solution-approach}
Let's write a method in Java for solving such problems, which will take three
parameters as input: sequence size, minimum and maximum number of elements in
a combination. The method will return a list of combinations of specified length.
```java
static List<Set<Integer>> combinationsOfElements(int size, int min, int max)
```
We call the method with the selection {<code>min=0;&nbsp;max=2</code>}
and get a list of combinations of specified length.
```java
// table setting problem
public static void main(String[] args) {
// four guests are invited
int[] arr = {1, 2, 3, 4};
// n - number of elements in a sequence
// k - maximum number of elements in a combination
int n = 4, k = 2;
// combinations of elements of specified length [0..2]
List<Set<Integer>> list = combinationsOfElements(n, 0, k);
// output
System.out.println("number of variants: " + list.size());
for (Set<Integer> set : list) {
System.out.print("[");
for (int i : set)
System.out.print(arr[i]);
System.out.print("]");
}
}
```
Output:
```
number of variants: 17
[][1][2][3][4][12][13][14][21][23][24][31][32][34][41][42][43]
```
## Combinations of elements of specified length {#combinations-of-length}
We write a method in Java using three nested `for` loops. Next, to check, we
call this method without selection {<code>min=0;&nbsp;max=size</code>} and get
all possible combinations. For example, let's take two sequences of three
elements: digits {`123`} and letters {`XYZ`}.
### Method description {#method-description}
We prepare two lists of combinations: the resulting list and the current list.
In the current list, the number of elements in all combinations will be the same.
The maximum number of elements in a combination is the size of the sequence.
We start with one empty combination and gradually increase the number of elements.
We bypass the possible number of elements and supplement the current combinations
with those indices that are not yet included. At each step, we increase the current
number of elements in the combinations by one and, if it gets into selection, then
we add these combinations to the result.
```java
/**
* @param size the sequence size (0 min max size)
* @param min minimum number of elements in a combination
* @param max maximum number of elements in a combination
* @return combinations of elements of specified length
*/
static List<Set<Integer>> combinationsOfElements(int size, int min, int max) {
// invalid incoming data, return an empty list of combinations
if (0 > min || min > max || max > size) return Collections.emptyList();
// resulting list of combinations
List<Set<Integer>> result = new ArrayList<>();
// current list of combinations, number of elements in all
// combinations is the same, start with one empty combination
List<Set<Integer>> sublist = Arrays.asList(Collections.<Integer>emptySet());
// bypass the possible number of elements in a combination
for (int l = 0; l < Math.min(size, max); l++) {
// if current number of elements gets into selection,
// then add these combinations to the result
if (l >= min) result.addAll(sublist);
// next list of combinations
List<Set<Integer>> nSublist = new ArrayList<>();
// bypass the current list of combinations
for (Set<Integer> comb : sublist) {
// bypass the indexes of the sequence elements
for (int i = 0; i < size; i++) {
// skip those indexes that already present
if (comb.contains(i)) continue;
// new combination, copy the current one
Set<Integer> nComb = new LinkedHashSet<>(comb);
// adding the current index
nComb.add(i);
// add in a new list of combinations
nSublist.add(nComb);
}
}
// update the current list of combinations
sublist = nSublist;
}
// add the current list of combinations to the result
result.addAll(sublist);
// return the final result
return result;
}
```
```java
// start the program and output the result
public static void main(String[] args) {
// two sequences of three elements
Integer[] arr1 = {1, 2, 3};
String[] arr2 = {"X", "Y", "Z"};
// number of sequence elements
int n = 3;
// all possible combinations of elements [0..n]
List<Set<Integer>> list = combinationsOfElements(n, 0, n);
// output
System.out.println("number of variants: " + list.size());
for (Object[] arr : Arrays.asList(arr1, arr2)) {
StringBuilder sb = new StringBuilder();
for (Set<Integer> set : list) {
sb.append("[");
for (int i : set) sb.append(arr[i]);
sb.append("]");
}
System.out.println(sb);
}
}
```
The output for this code see above: [combinations of three elements](#combinations-of-elements).

View file

@ -0,0 +1,173 @@
---
title: Cartesian product in parallel streams
description: Consider an algorithm for obtaining a Cartesian product using Java Streams. This solution is similar to three nested for loops, with the difference that...
sections: [Multithreading,Combinatorics,Direct product]
tags: [java,multithreading,combinatorics,algorithms,cartesian product]
canonical_url: /en/2021/10/05/cartesian-product-parallel-streams.html
url_translated: /ru/2021/10/04/cartesian-product-parallel-streams.html
title_translated: Декартово произведение в параллельных потоках
date: 2021.10.05
lang: en
---
Consider an algorithm for obtaining a *Cartesian product* using Java Streams. This solution is similar
to three nested `for` loops, with the difference that the outer loop is replaced with a stream for the
convenience of subsequent parallelization. Well use the `reduce` method with three parameters:
`identity`, `accumulator` and `combiner`.
*Algorithm with three nested loops:
[Cartesian product of sets]({{ '/en/2021/09/07/cartesian-product-of-sets.html' | relative_url }}).*
The incoming data is an arbitrary number of lists and their elements.
```
a = [A1,B1,C1,D1]
b = [A2,B2,C2]
c = [A3,B3]
d = [A4]
```
The number of possible combinations is the product of the number of elements in all lists:
```
4 * 3 * 2 * 1 = 24
```
We get a *stream of lists* `Stream<List<T>>` from the input data and call the `reduce` method:
{% capture md_list_into_div %}
- `identity` in our case it is a *list of lists* `List<List<T>>`, filled with
one empty value. We will use it as an intermediate result and as a final result.
- `accumulator` for each step of *reduction*, we define a method with two parameters:
intermediate result and current list. We supplement the intermediate result with elements
from the current list.
- `combiner` is used in parallel mode, combines the results of the work of streams,
obtains the *Cartesian product* of the results.
{% endcapture %}
<div>
{{- md_list_into_div | markdownify -}}
</div>
The step-by-step process of accumulating a *Cartesian product* looks like this:
```
result0: [[]]
list1: [A1,B1,C1,D1]
--------
result1: [[A1],[B1],[C1],[D1]]
list2: [A2,B2,C2]
--------
result2: [[A1,A2],[A1,B2],[A1,C2],[B1,A2],[B1,B2],...[D1,C2]]
list3: [A3,B3]
--------
result3: [[A1,A2,A3],[A1,A2,B3],[A1,B2,A3],[A1,B2,B3],[A1,C2,A3],...[D1,C2,B3]]
list4: [A4]
--------
result4: [[A1,A2,A3,A4],[A1,A2,B3,A4],[A1,B2,A3,A4],[A1,B2,B3,A4],...[D1,C2,B3,A4]]
```
### Combinations by columns {#combinations-by-columns}
```
Number of combinations: 24
[A1, A2, A3, A4] [B1, A2, A3, A4] [C1, A2, A3, A4] [D1, A2, A3, A4]
[A1, A2, B3, A4] [B1, A2, B3, A4] [C1, A2, B3, A4] [D1, A2, B3, A4]
[A1, B2, A3, A4] [B1, B2, A3, A4] [C1, B2, A3, A4] [D1, B2, A3, A4]
[A1, B2, B3, A4] [B1, B2, B3, A4] [C1, B2, B3, A4] [D1, B2, B3, A4]
[A1, C2, A3, A4] [B1, C2, A3, A4] [C1, C2, A3, A4] [D1, C2, A3, A4]
[A1, C2, B3, A4] [B1, C2, B3, A4] [C1, C2, B3, A4] [D1, C2, B3, A4]
```
## Combinations of elements in parallel streams {#combinations-of-elements-in-parallel-streams}
In parallel mode, the speed of the algorithm increases when multiplying a *large number of small lists*,
for example, 20 lists of 2 elements or 15 lists of 3 elements. The computation time reduces by *one and
a half to two* times. In other cases, the computation time is about the same as for three nested `for`
loops.
```java
/**
* @param lists an arbitrary number of lists
* @param <T> the type of elements in lists
* @return the Cartesian product of the passed lists
*/
public static <T> List<List<T>> cartesianProduct(List<List<T>> lists) {
// incoming data is not null
if (lists == null) return Collections.emptyList();
// stream of lists Stream<List<T>>
return lists.stream()
// enable parallel mode
.parallel()
// discard null and empty lists
.filter(list -> list != null && list.size() > 0)
// reduce the stream of lists into one list, get a Cartesian product
// reduce(identity, accumulator, combiner)
.reduce( // intermediate result, contains one empty value
Collections.singletonList(Collections.emptyList()),
// bypass the received lists and supplement the intermediate result
// with their elements, at each step obtain a new intermediate result
(result, list) -> {
// next intermediate result
List<List<T>> nResult = new ArrayList<>(result.size() * list.size());
// rows of the current intermediate result
for (List<T> row : result) {
// elements of the current list
for (T el : list) {
// a new row for the next intermediate result
List<T> nRow = new ArrayList<>(row.size() + 1);
// add the current row
nRow.addAll(row);
// add the current element
nRow.add(el);
// add to the next intermediate result
nResult.add(nRow);
}
}
// pass to the next iteration
return nResult;
},
// is used in parallel mode, combines the results of the work
// of streams, obtains the Cartesian product of the results
(result1, result2) -> {
// combined result
List<List<T>> result = new ArrayList<>(result1.size() * result2.size());
// bypass the results
for (List<T> comb1 : result1) {
for (List<T> comb2 : result2) {
// add up the combinations
List<T> comb = new ArrayList<>(comb1.size() + comb2.size());
comb.addAll(comb1);
comb.addAll(comb2);
result.add(comb);
}
}
return result;
});
}
```
```java
// start the program and output the result
public static void main(String[] args) {
// an arbitrary number of lists and their elements
List<String> a = Arrays.asList("A1", "B1", "C1", "D1");
List<String> b = Arrays.asList("A2", "B2", "C2");
List<String> c = Arrays.asList("A3", "B3");
List<String> d = Collections.singletonList("A4");
// cartesian product
List<List<String>> cp = cartesianProduct(Arrays.asList(a, b, c, d));
// output
System.out.println("Number of combinations: " + cp.size());
// combinations by columns
int rows = 6;
IntStream.range(0, rows).forEach(i -> System.out.println(
IntStream.range(0, cp.size())
.filter(j -> j % rows == i)
.mapToObj(j -> cp.get(j).toString())
.collect(Collectors.joining(" "))));
}
```
The output for this code see above: [combinations by columns](#combinations-by-columns).

63
jekyll_site/en/index.md Normal file
View file

@ -0,0 +1,63 @@
---
title: Code with comments
description: Notes about programming with code snippets and comments. Problem solutions and solution descriptions.
sections: [Problem solutions and solution descriptions]
tags: [java,combinatorics,algorithms,implementation,sets,subsets,lists,arrays,loops,nested loops]
canonical_url: /en/
url_translated: /ru/
title_translated: Код с комментариями
lang: en
---
{%- assign articles = "" | split: "" %}
{%- assign articles = articles | push: "Cartesian product in parallel streams" %}
{%- capture article_brief %}
Consider an algorithm for obtaining a *Cartesian product* using Java Streams. This solution is similar
to three nested `for` loops, with the difference that the outer loop is replaced with a stream for the
convenience of subsequent parallelization. Well use the `reduce` method with three parameters:
`identity`, `accumulator` and `combiner`.
In parallel mode, the speed of the algorithm increases when multiplying a *large number of small lists*,
for example, 20 lists of 2 elements or 15 lists of 3 elements. The computation time reduces by *one and
a half to two* times. In other cases, the computation time is about the same as for three nested `for`
loops.
{%- endcapture %}
{%- assign articles = articles | push: article_brief %}
{%- assign articles = articles | push: "Combinations of sequence elements" %}
{%- capture article_brief %}
Consider a problem where you need to get all possible combinations of sequence elements, in which
the number of elements in the combination does not exceed a given maximum, and let's write a method
in Java with the appropriate filter for the minimum and maximum number of elements.
An *arrangement* is an ordered set of {`k`} distinct elements from a set of distinct {`n`} elements,
where {<code>k&nbsp;&le;&nbsp;n</code>}. If {<code>k&nbsp;=&nbsp;n</code>}, then this ordered set
is a *permutation*. For the universality of the solution, we'll also consider *permutations* as
a special case of *arrangement*.
{%- endcapture %}
{%- assign articles = articles | push: article_brief %}
{%- assign articles = articles | push: "Combinations of elements by columns" %}
{%- capture article_brief %}
In a two-dimensional array, data is stored row-wise. Consider an algorithm for obtaining
a *Cartesian product* by columns using three nested loops. The number of rows and columns
of the table can be arbitrary. We multiply the columns sequentially and accumulate the
result. The values do not necessarily have to be populated we discard the null elements.
{%- endcapture %}
{%- assign articles = articles | push: article_brief %}
{%- assign articles = articles | push: "Pascal's Triangle in Java" %}
{%- capture article_brief %}
Consider a variant of the implementation of *Pascal's triangle* in Java. For the simplicity
of storing and processing data, we represent the triangle as a two-dimensional array, in which
the elements of the first row and column are equal to one, and all other elements are the sum
of the two previous elements in the row and column.
{%- endcapture %}
{%- assign articles = articles | push: article_brief %}
{%- assign articles = articles | push: "Cartesian product of sets" %}
{%- capture article_brief %}
Consider an algorithm for obtaining a *Cartesian product* of multiple sets using three nested
loops. The number of sets and their elements can be arbitrary. We multiply the sets sequentially
and accumulate the result. The order does not matter, since the product does not change due to the
permutation of the multipliers. As a result, the order will be different, but the combinations will
be the same.
{%- endcapture %}
{%- assign articles = articles | push: article_brief %}
{%- include main_page.html articles = articles -%}

View file

@ -0,0 +1,32 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="82.312663pt" height="44.923737pt" viewBox="-.239051 -.233566 82.312663 44.923737">
<defs>
<path id="g3-33" d="M2.6397-9.583259C2.6397-10.042337 2.252353-10.25753 1.951083-10.25753S1.20508-10.056683 1.248119-9.454143L1.764582-2.883585C1.778928-2.6397 1.807621-2.582315 1.936736-2.582315C2.080198-2.582315 2.108891-2.625354 2.123237-2.883585L2.6397-9.583259ZM2.6397-.702964C2.6397-1.075965 2.324084-1.391581 1.951083-1.391581C1.549389-1.391581 1.248119-1.075965 1.248119-.688617C1.248119-.315616 1.563735 0 1.936736 0C2.33843 0 2.6397-.315616 2.6397-.702964Z"/>
<path id="g3-40" d="M4.662514 3.486126C4.662514 3.443087 4.662514 3.414395 4.418628 3.170509C2.984009 1.721543 2.180622-.645579 2.180622-3.572203C2.180622-6.355365 2.854893-8.751179 4.519052-10.44403C4.662514-10.573146 4.662514-10.601839 4.662514-10.644877C4.662514-10.730954 4.590783-10.759647 4.533398-10.759647C4.346897-10.759647 3.170509-9.726721 2.467546-8.320793C1.73589-6.871828 1.405927-5.336785 1.405927-3.572203C1.405927-2.295391 1.606774-.588194 2.352776 .946849C3.199202 2.668392 4.37559 3.600895 4.533398 3.600895C4.590783 3.600895 4.662514 3.572203 4.662514 3.486126Z"/>
<path id="g3-41" d="M4.045627-3.572203C4.045627-4.662514 3.902165-6.441442 3.098778-8.105601C2.252353-9.827144 1.075965-10.759647 .918157-10.759647C.860772-10.759647 .789041-10.730954 .789041-10.644877C.789041-10.601839 .789041-10.573146 1.032926-10.329261C2.467546-8.880295 3.270933-6.513173 3.270933-3.586549C3.270933-.803387 2.596661 1.592428 .932503 3.285279C.789041 3.414395 .789041 3.443087 .789041 3.486126C.789041 3.572203 .860772 3.600895 .918157 3.600895C1.104657 3.600895 2.281045 2.567969 2.984009 1.162042C3.715665-.30127 4.045627-1.850659 4.045627-3.572203Z"/>
<path id="g2-107" d="M4.031281-9.597605C4.045627-9.65499 4.07432-9.741067 4.07432-9.812798C4.07432-9.95626 3.930858-9.95626 3.902165-9.95626C3.887819-9.95626 3.371356-9.913221 3.113124-9.884529C2.869239-9.870183 2.654046-9.84149 2.395815-9.827144C2.051506-9.798452 1.951083-9.784105 1.951083-9.525874C1.951083-9.382412 2.094545-9.382412 2.238007-9.382412C2.969663-9.382412 2.969663-9.253296 2.969663-9.109834C2.969663-9.052449 2.969663-9.023757 2.897932-8.765526L.846426-.559502C.789041-.344309 .789041-.315616 .789041-.229539C.789041 .086077 1.032926 .143462 1.176388 .143462C1.578082 .143462 1.664159-.172154 1.778928-.616886L2.453199-3.299625C3.486126-3.184855 4.103012-2.75447 4.103012-2.065852C4.103012-1.979775 4.103012-1.92239 4.059973-1.707197C4.002589-1.492004 4.002589-1.31985 4.002589-1.248119C4.002589-.41604 4.547744 .143462 5.2794 .143462C5.939325 .143462 6.283634-.459078 6.398403-.659925C6.699673-1.190734 6.886174-1.994121 6.886174-2.051506C6.886174-2.123237 6.828789-2.180622 6.742712-2.180622C6.613596-2.180622 6.59925-2.123237 6.541865-1.893698C6.341018-1.147696 6.039748-.143462 5.308092-.143462C5.021168-.143462 4.834668-.286924 4.834668-.832079C4.834668-1.104657 4.892053-1.420273 4.949438-1.635466C5.006822-1.893698 5.006822-1.908044 5.006822-2.080198C5.006822-2.926624 4.246474-3.400048 2.926624-3.572203C3.443087-3.887819 3.95955-4.447321 4.160397-4.662514C4.97813-5.58067 5.537632-6.039748 6.197557-6.039748C6.527519-6.039748 6.613596-5.953671 6.71402-5.867594C6.18321-5.810209 5.982364-5.437208 5.982364-5.150284C5.982364-4.805976 6.254941-4.691206 6.455788-4.691206C6.843135-4.691206 7.187444-5.021168 7.187444-5.480247C7.187444-5.896286 6.857482-6.326672 6.211903-6.326672C5.422862-6.326672 4.777283-5.767171 3.758703-4.619475C3.615241-4.447321 3.084432-3.902165 2.553623-3.701318L4.031281-9.597605Z"/>
<path id="g2-110" d="M2.955316-4.203435C2.984009-4.289513 3.342664-5.006822 3.873473-5.465901C4.246474-5.810209 4.734245-6.039748 5.293746-6.039748C5.867594-6.039748 6.068441-5.609363 6.068441-5.035515C6.068441-4.217782 5.480247-2.582315 5.193323-1.807621C5.064207-1.463312 4.992476-1.276811 4.992476-1.01858C4.992476-.373001 5.437208 .143462 6.125826 .143462C7.460022 .143462 7.962139-1.965429 7.962139-2.051506C7.962139-2.123237 7.904754-2.180622 7.818677-2.180622C7.689561-2.180622 7.675215-2.137583 7.603484-1.893698C7.273521-.71731 6.728366-.143462 6.168864-.143462C6.025402-.143462 5.795863-.157808 5.795863-.616886C5.795863-.975541 5.953671-1.405927 6.039748-1.606774C6.326672-2.395815 6.929213-4.002589 6.929213-4.820322C6.929213-5.681093 6.427096-6.326672 5.336785-6.326672C4.059973-6.326672 3.385702-5.422862 3.127471-5.064207C3.084432-5.88194 2.496238-6.326672 1.865005-6.326672C1.405927-6.326672 1.090311-6.054095 .846426-5.566324C.588194-5.049861 .387347-4.189089 .387347-4.131704S.444732-4.002589 .545155-4.002589C.659925-4.002589 .674271-4.016935 .760348-4.346897C.989888-5.222015 1.248119-6.039748 1.821967-6.039748C2.151929-6.039748 2.266699-5.810209 2.266699-5.379823C2.266699-5.064207 2.123237-4.504705 2.022814-4.059973L1.62112-2.510584C1.563735-2.238007 1.405927-1.592428 1.334196-1.334196C1.233773-.961195 1.075965-.286924 1.075965-.215193C1.075965-.014346 1.233773 .143462 1.448966 .143462C1.62112 .143462 1.821967 .057385 1.936736-.157808C1.965429-.229539 2.094545-.731656 2.166276-1.01858L2.481892-2.309738L2.955316-4.203435Z"/>
<path id="g1-0" d="M9.454143-3.299625C9.698028-3.299625 9.95626-3.299625 9.95626-3.586549S9.698028-3.873473 9.454143-3.873473H1.692851C1.448966-3.873473 1.190734-3.873473 1.190734-3.586549S1.448966-3.299625 1.692851-3.299625H9.454143Z"/>
<path id="g5-48" d="M4.582814-3.188045C4.582814-3.985056 4.533001-4.782067 4.184309-5.519303C3.726027-6.475716 2.909091-6.635118 2.49066-6.635118C1.892902-6.635118 1.165629-6.37609 .757161-5.449564C.438356-4.762142 .388543-3.985056 .388543-3.188045C.388543-2.440847 .428394-1.544209 .836862-.787049C1.265255 .019925 1.992528 .219178 2.480697 .219178C3.01868 .219178 3.775841 .009963 4.214197-.936488C4.533001-1.62391 4.582814-2.400996 4.582814-3.188045ZM2.480697 0C2.092154 0 1.504359-.249066 1.325031-1.205479C1.215442-1.803238 1.215442-2.719801 1.215442-3.307597C1.215442-3.945205 1.215442-4.60274 1.295143-5.140722C1.484433-6.326276 2.231631-6.41594 2.480697-6.41594C2.809465-6.41594 3.466999-6.236613 3.656289-5.250311C3.755915-4.692403 3.755915-3.935243 3.755915-3.307597C3.755915-2.560399 3.755915-1.882939 3.646326-1.24533C3.496887-.298879 2.929016 0 2.480697 0Z"/>
<path id="g5-61" d="M6.844334-3.257783C6.993773-3.257783 7.183064-3.257783 7.183064-3.457036S6.993773-3.656289 6.854296-3.656289H.886675C.747198-3.656289 .557908-3.656289 .557908-3.457036S.747198-3.257783 .896638-3.257783H6.844334ZM6.854296-1.325031C6.993773-1.325031 7.183064-1.325031 7.183064-1.524284S6.993773-1.723537 6.844334-1.723537H.896638C.747198-1.723537 .557908-1.723537 .557908-1.524284S.747198-1.325031 .886675-1.325031H6.854296Z"/>
<path id="g0-88" d="M18.162284 20.084674L19.898173 15.493891H19.539518C18.980017 16.985896 17.45932 17.961437 15.809508 18.391823C15.508238 18.463554 14.10231 18.836555 11.347841 18.836555H2.697085L9.999298 10.271876C10.099722 10.157107 10.128414 10.114068 10.128414 10.042337C10.128414 10.013645 10.128414 9.970606 10.027991 9.827144L3.342664 .688617H11.204379C13.126769 .688617 14.432273 .889464 14.561389 .918157C15.336083 1.032926 16.584202 1.276811 17.717552 1.994121C18.076207 2.22366 19.051748 2.869239 19.539518 4.031281H19.898173L18.162284 0H1.20508C.875118 0 .860772 .014346 .817733 .100423C.803387 .143462 .803387 .41604 .803387 .573848L8.392524 10.960493L.961195 19.668634C.817733 19.840789 .817733 19.91252 .817733 19.926866C.817733 20.084674 .946849 20.084674 1.20508 20.084674H18.162284Z"/>
<path id="g4-107" d="M2.859278-6.804483C2.859278-6.814446 2.859278-6.914072 2.729763-6.914072C2.500623-6.914072 1.77335-6.834371 1.514321-6.814446C1.43462-6.804483 1.325031-6.794521 1.325031-6.615193C1.325031-6.495641 1.414695-6.495641 1.564134-6.495641C2.042341-6.495641 2.062267-6.425903 2.062267-6.326276L2.032379-6.127024L.587796-.388543C.547945-.249066 .547945-.229141 .547945-.169365C.547945 .059776 .747198 .109589 .836862 .109589C.966376 .109589 1.115816 .019925 1.175592-.099626C1.225405-.18929 1.673724-2.032379 1.733499-2.281445C2.072229-2.251557 2.889166-2.092154 2.889166-1.43462C2.889166-1.364882 2.889166-1.325031 2.859278-1.225405C2.839352-1.105853 2.819427-.986301 2.819427-.876712C2.819427-.288917 3.217933 .109589 3.73599 .109589C4.034869 .109589 4.303861-.049813 4.523039-.418431C4.772105-.856787 4.881694-1.404732 4.881694-1.424658C4.881694-1.524284 4.79203-1.524284 4.762142-1.524284C4.662516-1.524284 4.652553-1.484433 4.622665-1.344956C4.423412-.617684 4.194271-.109589 3.755915-.109589C3.566625-.109589 3.437111-.219178 3.437111-.577833C3.437111-.747198 3.476961-.976339 3.516812-1.135741C3.556663-1.305106 3.556663-1.344956 3.556663-1.444583C3.556663-2.092154 2.929016-2.381071 2.082192-2.49066C2.391034-2.669988 2.709838-2.988792 2.938979-3.227895C3.417186-3.755915 3.875467-4.184309 4.363636-4.184309C4.423412-4.184309 4.433375-4.184309 4.4533-4.174346C4.572852-4.154421 4.582814-4.154421 4.662516-4.094645C4.682441-4.084682 4.682441-4.07472 4.702366-4.054795C4.224159-4.024907 4.134496-3.636364 4.134496-3.516812C4.134496-3.35741 4.244085-3.16812 4.513076-3.16812C4.772105-3.16812 5.061021-3.387298 5.061021-3.775841C5.061021-4.07472 4.83188-4.403487 4.383562-4.403487C4.104608-4.403487 3.646326-4.323786 2.929016-3.526775C2.590286-3.148194 2.201743-2.749689 1.823163-2.600249L2.859278-6.804483Z"/>
<path id="g4-110" d="M.876712-.587796C.846824-.438356 .787049-.209215 .787049-.159402C.787049 .019925 .926526 .109589 1.075965 .109589C1.195517 .109589 1.374844 .029888 1.444583-.169365C1.454545-.18929 1.574097-.657534 1.633873-.9066L1.853051-1.803238C1.912827-2.022416 1.972603-2.241594 2.022416-2.470735C2.062267-2.6401 2.141968-2.929016 2.15193-2.968867C2.30137-3.277709 2.82939-4.184309 3.775841-4.184309C4.224159-4.184309 4.313823-3.815691 4.313823-3.486924C4.313823-2.86924 3.825654-1.594022 3.666252-1.165629C3.576588-.936488 3.566625-.816936 3.566625-.707347C3.566625-.239103 3.915318 .109589 4.383562 .109589C5.32005 .109589 5.688667-1.344956 5.688667-1.424658C5.688667-1.524284 5.599004-1.524284 5.569116-1.524284C5.469489-1.524284 5.469489-1.494396 5.419676-1.344956C5.220423-.667497 4.891656-.109589 4.403487-.109589C4.234122-.109589 4.164384-.209215 4.164384-.438356C4.164384-.687422 4.254047-.926526 4.343711-1.145704C4.533001-1.673724 4.951432-2.769614 4.951432-3.337484C4.951432-4.004981 4.523039-4.403487 3.805729-4.403487C2.909091-4.403487 2.420922-3.765878 2.251557-3.536737C2.201743-4.094645 1.793275-4.403487 1.334994-4.403487S.687422-4.014944 .587796-3.835616C.428394-3.496887 .288917-2.909091 .288917-2.86924C.288917-2.769614 .388543-2.769614 .408468-2.769614C.508095-2.769614 .518057-2.779577 .577833-2.998755C.747198-3.706102 .946451-4.184309 1.305106-4.184309C1.504359-4.184309 1.613948-4.054795 1.613948-3.726027C1.613948-3.516812 1.58406-3.407223 1.454545-2.889166L.876712-.587796Z"/>
</defs>
<g fill="#222" stroke="#222" style="fill: var(--color, #222); stroke: var(--color, #222);" stroke-width="0.3" transform="matrix(1.13 0 0 1.13 -63.986043 -62.517865)">
<use x="63.784475" y="59.522336" xlink:href="#g4-110"/>
<use x="56.413267" y="63.826203" xlink:href="#g0-88"/>
<use x="57.659296" y="94.65519" xlink:href="#g4-107"/>
<use x="63.159516" y="94.65519" xlink:href="#g5-61"/>
<use x="70.908264" y="94.65519" xlink:href="#g5-48"/>
<use x="98.845683" y="67.749844" xlink:href="#g2-110"/>
<use x="107.230806" y="67.749844" xlink:href="#g3-33"/>
<rect x="80.722118" y="73.581689" height=".573822" width="48.534214"/>
<use x="80.722118" y="87.295916" xlink:href="#g3-40"/>
<use x="86.184907" y="87.295916" xlink:href="#g2-110"/>
<use x="97.758026" y="87.295916" xlink:href="#g1-0"/>
<use x="112.104214" y="87.295916" xlink:href="#g2-107"/>
<use x="119.89161" y="87.295916" xlink:href="#g3-41"/>
<use x="125.354398" y="87.295916" xlink:href="#g3-33"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -0,0 +1,75 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="374.279367pt" height="47.44548pt" viewBox="-.239051 -.233139 374.279367 47.44548">
<defs>
<path id="g2-58" d="M2.6397-.688617C2.6397-1.104657 2.295391-1.391581 1.951083-1.391581C1.535043-1.391581 1.248119-1.047272 1.248119-.702964C1.248119-.286924 1.592428 0 1.936736 0C2.352776 0 2.6397-.344309 2.6397-.688617Z"/>
<path id="g2-107" d="M4.031281-9.597605C4.045627-9.65499 4.07432-9.741067 4.07432-9.812798C4.07432-9.95626 3.930858-9.95626 3.902165-9.95626C3.887819-9.95626 3.371356-9.913221 3.113124-9.884529C2.869239-9.870183 2.654046-9.84149 2.395815-9.827144C2.051506-9.798452 1.951083-9.784105 1.951083-9.525874C1.951083-9.382412 2.094545-9.382412 2.238007-9.382412C2.969663-9.382412 2.969663-9.253296 2.969663-9.109834C2.969663-9.052449 2.969663-9.023757 2.897932-8.765526L.846426-.559502C.789041-.344309 .789041-.315616 .789041-.229539C.789041 .086077 1.032926 .143462 1.176388 .143462C1.578082 .143462 1.664159-.172154 1.778928-.616886L2.453199-3.299625C3.486126-3.184855 4.103012-2.75447 4.103012-2.065852C4.103012-1.979775 4.103012-1.92239 4.059973-1.707197C4.002589-1.492004 4.002589-1.31985 4.002589-1.248119C4.002589-.41604 4.547744 .143462 5.2794 .143462C5.939325 .143462 6.283634-.459078 6.398403-.659925C6.699673-1.190734 6.886174-1.994121 6.886174-2.051506C6.886174-2.123237 6.828789-2.180622 6.742712-2.180622C6.613596-2.180622 6.59925-2.123237 6.541865-1.893698C6.341018-1.147696 6.039748-.143462 5.308092-.143462C5.021168-.143462 4.834668-.286924 4.834668-.832079C4.834668-1.104657 4.892053-1.420273 4.949438-1.635466C5.006822-1.893698 5.006822-1.908044 5.006822-2.080198C5.006822-2.926624 4.246474-3.400048 2.926624-3.572203C3.443087-3.887819 3.95955-4.447321 4.160397-4.662514C4.97813-5.58067 5.537632-6.039748 6.197557-6.039748C6.527519-6.039748 6.613596-5.953671 6.71402-5.867594C6.18321-5.810209 5.982364-5.437208 5.982364-5.150284C5.982364-4.805976 6.254941-4.691206 6.455788-4.691206C6.843135-4.691206 7.187444-5.021168 7.187444-5.480247C7.187444-5.896286 6.857482-6.326672 6.211903-6.326672C5.422862-6.326672 4.777283-5.767171 3.758703-4.619475C3.615241-4.447321 3.084432-3.902165 2.553623-3.701318L4.031281-9.597605Z"/>
<path id="g3-33" d="M2.6397-9.583259C2.6397-10.042337 2.252353-10.25753 1.951083-10.25753S1.20508-10.056683 1.248119-9.454143L1.764582-2.883585C1.778928-2.6397 1.807621-2.582315 1.936736-2.582315C2.080198-2.582315 2.108891-2.625354 2.123237-2.883585L2.6397-9.583259ZM2.6397-.702964C2.6397-1.075965 2.324084-1.391581 1.951083-1.391581C1.549389-1.391581 1.248119-1.075965 1.248119-.688617C1.248119-.315616 1.563735 0 1.936736 0C2.33843 0 2.6397-.315616 2.6397-.702964Z"/>
<path id="g3-40" d="M4.662514 3.486126C4.662514 3.443087 4.662514 3.414395 4.418628 3.170509C2.984009 1.721543 2.180622-.645579 2.180622-3.572203C2.180622-6.355365 2.854893-8.751179 4.519052-10.44403C4.662514-10.573146 4.662514-10.601839 4.662514-10.644877C4.662514-10.730954 4.590783-10.759647 4.533398-10.759647C4.346897-10.759647 3.170509-9.726721 2.467546-8.320793C1.73589-6.871828 1.405927-5.336785 1.405927-3.572203C1.405927-2.295391 1.606774-.588194 2.352776 .946849C3.199202 2.668392 4.37559 3.600895 4.533398 3.600895C4.590783 3.600895 4.662514 3.572203 4.662514 3.486126Z"/>
<path id="g3-41" d="M4.045627-3.572203C4.045627-4.662514 3.902165-6.441442 3.098778-8.105601C2.252353-9.827144 1.075965-10.759647 .918157-10.759647C.860772-10.759647 .789041-10.730954 .789041-10.644877C.789041-10.601839 .789041-10.573146 1.032926-10.329261C2.467546-8.880295 3.270933-6.513173 3.270933-3.586549C3.270933-.803387 2.596661 1.592428 .932503 3.285279C.789041 3.414395 .789041 3.443087 .789041 3.486126C.789041 3.572203 .860772 3.600895 .918157 3.600895C1.104657 3.600895 2.281045 2.567969 2.984009 1.162042C3.715665-.30127 4.045627-1.850659 4.045627-3.572203Z"/>
<path id="g3-43" d="M5.724132-3.313971H9.683682C9.884529-3.313971 10.14276-3.313971 10.14276-3.572203C10.14276-3.84478 9.898875-3.84478 9.683682-3.84478H5.724132V-7.80433C5.724132-8.005177 5.724132-8.263409 5.465901-8.263409C5.193323-8.263409 5.193323-8.019523 5.193323-7.80433V-3.84478H1.233773C1.032926-3.84478 .774695-3.84478 .774695-3.586549C.774695-3.313971 1.01858-3.313971 1.233773-3.313971H5.193323V.645579C5.193323 .846426 5.193323 1.104657 5.451554 1.104657C5.724132 1.104657 5.724132 .860772 5.724132 .645579V-3.313971Z"/>
<path id="g3-48" d="M6.427096-4.590783C6.427096-5.781517 6.355365-6.943559 5.838902-8.03387C5.250708-9.224604 4.217782-9.54022 3.514818-9.54022C2.682739-9.54022 1.664159-9.12418 1.133349-7.933446C.731656-7.029636 .588194-6.140172 .588194-4.590783C.588194-3.199202 .688617-2.151929 1.20508-1.133349C1.764582-.043039 2.75447 .30127 3.500472 .30127C4.748591 .30127 5.465901-.444732 5.88194-1.276811C6.398403-2.352776 6.427096-3.758703 6.427096-4.590783ZM3.500472 .014346C3.041393 .014346 2.108891-.243885 1.836313-1.807621C1.678505-2.668392 1.678505-3.758703 1.678505-4.762937C1.678505-5.939325 1.678505-7.000943 1.908044-7.847369C2.151929-8.808564 2.883585-9.253296 3.500472-9.253296C4.045627-9.253296 4.877707-8.923334 5.150284-7.689561C5.336785-6.871828 5.336785-5.738478 5.336785-4.762937C5.336785-3.801742 5.336785-2.711431 5.178977-1.836313C4.906399-.258232 4.002589 .014346 3.500472 .014346Z"/>
<path id="g3-49" d="M4.131704-9.195911C4.131704-9.525874 4.131704-9.54022 3.84478-9.54022C3.500472-9.152873 2.783162-8.622064 1.305504-8.622064V-8.206024C1.635466-8.206024 2.352776-8.206024 3.141817-8.579025V-1.104657C3.141817-.588194 3.098778-.41604 1.836313-.41604H1.391581V0C1.778928-.028692 3.170509-.028692 3.643934-.028692S5.494593-.028692 5.88194 0V-.41604H5.437208C4.174743-.41604 4.131704-.588194 4.131704-1.104657V-9.195911Z"/>
<path id="g3-50" d="M6.312326-2.410161H5.99671C5.953671-2.166276 5.838902-1.377235 5.69544-1.147696C5.595016-1.01858 4.777283-1.01858 4.346897-1.01858H1.692851C2.080198-1.348542 2.955316-2.266699 3.328317-2.611008C5.508939-4.619475 6.312326-5.365477 6.312326-6.785751C6.312326-8.435563 5.006822-9.54022 3.342664-9.54022S.702964-8.119947 .702964-6.886174C.702964-6.154518 1.334196-6.154518 1.377235-6.154518C1.678505-6.154518 2.051506-6.369711 2.051506-6.828789C2.051506-7.230483 1.778928-7.50306 1.377235-7.50306C1.248119-7.50306 1.219427-7.50306 1.176388-7.488714C1.448966-8.464255 2.22366-9.12418 3.156163-9.12418C4.37559-9.12418 5.121592-8.105601 5.121592-6.785751C5.121592-5.566324 4.418628-4.504705 3.600895-3.586549L.702964-.344309V0H5.939325L6.312326-2.410161Z"/>
<path id="g3-51" d="M2.6397-5.150284C2.395815-5.135938 2.33843-5.121592 2.33843-4.992476C2.33843-4.849014 2.410161-4.849014 2.668392-4.849014H3.328317C4.547744-4.849014 5.092899-3.84478 5.092899-2.467546C5.092899-.588194 4.117358-.086077 3.414395-.086077C2.725777-.086077 1.549389-.41604 1.133349-1.362889C1.592428-1.291158 2.008467-1.549389 2.008467-2.065852C2.008467-2.481892 1.707197-2.768816 1.305504-2.768816C.961195-2.768816 .588194-2.567969 .588194-2.022814C.588194-.746002 1.865005 .30127 3.457433 .30127C5.16463 .30127 6.427096-1.004234 6.427096-2.453199C6.427096-3.773049 5.365477-4.805976 3.988242-5.049861C5.236361-5.408516 6.039748-6.455788 6.039748-7.574791C6.039748-8.708141 4.86336-9.54022 3.471779-9.54022C2.03716-9.54022 .975541-8.665102 .975541-7.61783C.975541-7.043982 1.420273-6.929213 1.635466-6.929213C1.936736-6.929213 2.281045-7.144405 2.281045-7.574791C2.281045-8.03387 1.936736-8.234716 1.62112-8.234716C1.535043-8.234716 1.506351-8.234716 1.463312-8.22037C2.008467-9.195911 3.35701-9.195911 3.428741-9.195911C3.902165-9.195911 4.834668-8.980718 4.834668-7.574791C4.834668-7.302214 4.791629-6.498827 4.37559-5.88194C3.945204-5.250708 3.457433-5.207669 3.070086-5.193323L2.6397-5.150284Z"/>
<path id="g3-54" d="M1.764582-4.992476C1.764582-8.622064 3.529164-9.195911 4.303859-9.195911C4.820322-9.195911 5.336785-9.038103 5.609363-8.607717C5.437208-8.607717 4.892053-8.607717 4.892053-8.019523C4.892053-7.703907 5.107246-7.431329 5.480247-7.431329C5.838902-7.431329 6.082787-7.646522 6.082787-8.062562C6.082787-8.808564 5.537632-9.54022 4.289513-9.54022C2.481892-9.54022 .588194-7.689561 .588194-4.533398C.588194-.588194 2.309738 .30127 3.529164 .30127C5.092899 .30127 6.427096-1.061618 6.427096-2.926624C6.427096-4.834668 5.092899-6.111479 3.65828-6.111479C2.381468-6.111479 1.908044-5.006822 1.764582-4.605129V-4.992476ZM3.529164-.086077C2.625354-.086077 2.194968-.889464 2.065852-1.190734C1.936736-1.563735 1.793274-2.266699 1.793274-3.270933C1.793274-4.404282 2.309738-5.824555 3.600895-5.824555C4.389936-5.824555 4.805976-5.293746 5.021168-4.805976C5.250708-4.275166 5.250708-3.557857 5.250708-2.94097C5.250708-2.209314 5.250708-1.563735 4.97813-1.01858C4.619475-.329963 4.103012-.086077 3.529164-.086077Z"/>
<path id="g3-61" d="M9.683682-4.648167C9.884529-4.648167 10.14276-4.648167 10.14276-4.906399C10.14276-5.178977 9.898875-5.178977 9.683682-5.178977H1.233773C1.032926-5.178977 .774695-5.178977 .774695-4.920745C.774695-4.648167 1.01858-4.648167 1.233773-4.648167H9.683682ZM9.683682-1.979775C9.884529-1.979775 10.14276-1.979775 10.14276-2.238007C10.14276-2.510584 9.898875-2.510584 9.683682-2.510584H1.233773C1.032926-2.510584 .774695-2.510584 .774695-2.252353C.774695-1.979775 1.01858-1.979775 1.233773-1.979775H9.683682Z"/>
<path id="g4-107" d="M2.859278-6.804483C2.859278-6.814446 2.859278-6.914072 2.729763-6.914072C2.500623-6.914072 1.77335-6.834371 1.514321-6.814446C1.43462-6.804483 1.325031-6.794521 1.325031-6.615193C1.325031-6.495641 1.414695-6.495641 1.564134-6.495641C2.042341-6.495641 2.062267-6.425903 2.062267-6.326276L2.032379-6.127024L.587796-.388543C.547945-.249066 .547945-.229141 .547945-.169365C.547945 .059776 .747198 .109589 .836862 .109589C.966376 .109589 1.115816 .019925 1.175592-.099626C1.225405-.18929 1.673724-2.032379 1.733499-2.281445C2.072229-2.251557 2.889166-2.092154 2.889166-1.43462C2.889166-1.364882 2.889166-1.325031 2.859278-1.225405C2.839352-1.105853 2.819427-.986301 2.819427-.876712C2.819427-.288917 3.217933 .109589 3.73599 .109589C4.034869 .109589 4.303861-.049813 4.523039-.418431C4.772105-.856787 4.881694-1.404732 4.881694-1.424658C4.881694-1.524284 4.79203-1.524284 4.762142-1.524284C4.662516-1.524284 4.652553-1.484433 4.622665-1.344956C4.423412-.617684 4.194271-.109589 3.755915-.109589C3.566625-.109589 3.437111-.219178 3.437111-.577833C3.437111-.747198 3.476961-.976339 3.516812-1.135741C3.556663-1.305106 3.556663-1.344956 3.556663-1.444583C3.556663-2.092154 2.929016-2.381071 2.082192-2.49066C2.391034-2.669988 2.709838-2.988792 2.938979-3.227895C3.417186-3.755915 3.875467-4.184309 4.363636-4.184309C4.423412-4.184309 4.433375-4.184309 4.4533-4.174346C4.572852-4.154421 4.582814-4.154421 4.662516-4.094645C4.682441-4.084682 4.682441-4.07472 4.702366-4.054795C4.224159-4.024907 4.134496-3.636364 4.134496-3.516812C4.134496-3.35741 4.244085-3.16812 4.513076-3.16812C4.772105-3.16812 5.061021-3.387298 5.061021-3.775841C5.061021-4.07472 4.83188-4.403487 4.383562-4.403487C4.104608-4.403487 3.646326-4.323786 2.929016-3.526775C2.590286-3.148194 2.201743-2.749689 1.823163-2.600249L2.859278-6.804483Z"/>
<path id="g0-88" d="M18.162284 20.084674L19.898173 15.493891H19.539518C18.980017 16.985896 17.45932 17.961437 15.809508 18.391823C15.508238 18.463554 14.10231 18.836555 11.347841 18.836555H2.697085L9.999298 10.271876C10.099722 10.157107 10.128414 10.114068 10.128414 10.042337C10.128414 10.013645 10.128414 9.970606 10.027991 9.827144L3.342664 .688617H11.204379C13.126769 .688617 14.432273 .889464 14.561389 .918157C15.336083 1.032926 16.584202 1.276811 17.717552 1.994121C18.076207 2.22366 19.051748 2.869239 19.539518 4.031281H19.898173L18.162284 0H1.20508C.875118 0 .860772 .014346 .817733 .100423C.803387 .143462 .803387 .41604 .803387 .573848L8.392524 10.960493L.961195 19.668634C.817733 19.840789 .817733 19.91252 .817733 19.926866C.817733 20.084674 .946849 20.084674 1.20508 20.084674H18.162284Z"/>
<path id="g1-0" d="M9.454143-3.299625C9.698028-3.299625 9.95626-3.299625 9.95626-3.586549S9.698028-3.873473 9.454143-3.873473H1.692851C1.448966-3.873473 1.190734-3.873473 1.190734-3.586549S1.448966-3.299625 1.692851-3.299625H9.454143Z"/>
<path id="g5-48" d="M4.582814-3.188045C4.582814-3.985056 4.533001-4.782067 4.184309-5.519303C3.726027-6.475716 2.909091-6.635118 2.49066-6.635118C1.892902-6.635118 1.165629-6.37609 .757161-5.449564C.438356-4.762142 .388543-3.985056 .388543-3.188045C.388543-2.440847 .428394-1.544209 .836862-.787049C1.265255 .019925 1.992528 .219178 2.480697 .219178C3.01868 .219178 3.775841 .009963 4.214197-.936488C4.533001-1.62391 4.582814-2.400996 4.582814-3.188045ZM2.480697 0C2.092154 0 1.504359-.249066 1.325031-1.205479C1.215442-1.803238 1.215442-2.719801 1.215442-3.307597C1.215442-3.945205 1.215442-4.60274 1.295143-5.140722C1.484433-6.326276 2.231631-6.41594 2.480697-6.41594C2.809465-6.41594 3.466999-6.236613 3.656289-5.250311C3.755915-4.692403 3.755915-3.935243 3.755915-3.307597C3.755915-2.560399 3.755915-1.882939 3.646326-1.24533C3.496887-.298879 2.929016 0 2.480697 0Z"/>
<path id="g5-51" d="M2.889166-3.506849C3.706102-3.775841 4.283935-4.473225 4.283935-5.260274C4.283935-6.07721 3.407223-6.635118 2.450809-6.635118C1.444583-6.635118 .687422-6.03736 .687422-5.280199C.687422-4.951432 .9066-4.762142 1.195517-4.762142C1.504359-4.762142 1.703611-4.98132 1.703611-5.270237C1.703611-5.768369 1.235367-5.768369 1.085928-5.768369C1.39477-6.256538 2.052304-6.386052 2.410959-6.386052C2.819427-6.386052 3.367372-6.166874 3.367372-5.270237C3.367372-5.150685 3.347447-4.572852 3.088418-4.134496C2.789539-3.656289 2.450809-3.626401 2.201743-3.616438C2.122042-3.606476 1.882939-3.58655 1.8132-3.58655C1.733499-3.576588 1.663761-3.566625 1.663761-3.466999C1.663761-3.35741 1.733499-3.35741 1.902864-3.35741H2.34122C3.158157-3.35741 3.526775-2.67995 3.526775-1.703611C3.526775-.348692 2.839352-.059776 2.400996-.059776C1.972603-.059776 1.225405-.229141 .876712-.816936C1.225405-.767123 1.534247-.986301 1.534247-1.364882C1.534247-1.723537 1.265255-1.92279 .976339-1.92279C.737235-1.92279 .418431-1.783313 .418431-1.344956C.418431-.438356 1.344956 .219178 2.430884 .219178C3.646326 .219178 4.552927-.687422 4.552927-1.703611C4.552927-2.520548 3.92528-3.297634 2.889166-3.506849Z"/>
<path id="g5-61" d="M6.844334-3.257783C6.993773-3.257783 7.183064-3.257783 7.183064-3.457036S6.993773-3.656289 6.854296-3.656289H.886675C.747198-3.656289 .557908-3.656289 .557908-3.457036S.747198-3.257783 .896638-3.257783H6.844334ZM6.854296-1.325031C6.993773-1.325031 7.183064-1.325031 7.183064-1.524284S6.993773-1.723537 6.844334-1.723537H.896638C.747198-1.723537 .557908-1.723537 .557908-1.524284S.747198-1.325031 .886675-1.325031H6.854296Z"/>
</defs>
<g fill="#222" stroke="#222" style="fill: var(--color, #222); stroke: var(--color, #222);" stroke-width="0.3" transform="matrix(1.13 0 0 1.13 -63.986043 -62.403623)">
<use x="64.283777" y="61.653246" xlink:href="#g5-51"/>
<use x="56.413267" y="65.957113" xlink:href="#g0-88"/>
<use x="57.659296" y="96.7861" xlink:href="#g4-107"/>
<use x="63.159516" y="96.7861" xlink:href="#g5-61"/>
<use x="70.908264" y="96.7861" xlink:href="#g5-48"/>
<use x="98.845683" y="69.880754" xlink:href="#g3-51"/>
<use x="105.869268" y="69.880754" xlink:href="#g3-33"/>
<rect x="80.722118" y="75.712599" height=".573822" width="47.172666"/>
<use x="80.722118" y="89.426826" xlink:href="#g3-40"/>
<use x="86.184907" y="89.426826" xlink:href="#g3-51"/>
<use x="96.396488" y="89.426826" xlink:href="#g1-0"/>
<use x="110.742676" y="89.426826" xlink:href="#g2-107"/>
<use x="118.530072" y="89.426826" xlink:href="#g3-41"/>
<use x="123.99286" y="89.426826" xlink:href="#g3-33"/>
<use x="133.075293" y="79.586059" xlink:href="#g3-61"/>
<use x="149.181379" y="69.880754" xlink:href="#g3-51"/>
<use x="156.204965" y="69.880754" xlink:href="#g3-33"/>
<rect x="149.181379" y="75.712599" height=".573822" width="10.925551"/>
<use x="149.181379" y="89.426826" xlink:href="#g3-51"/>
<use x="156.204965" y="89.426826" xlink:href="#g3-33"/>
<use x="164.490441" y="79.586059" xlink:href="#g3-43"/>
<use x="179.799528" y="69.880754" xlink:href="#g3-51"/>
<use x="186.823113" y="69.880754" xlink:href="#g3-33"/>
<rect x="179.799528" y="75.712599" height=".573822" width="10.925551"/>
<use x="179.799528" y="89.426826" xlink:href="#g3-50"/>
<use x="186.823113" y="89.426826" xlink:href="#g3-33"/>
<use x="195.108589" y="79.586059" xlink:href="#g3-43"/>
<use x="210.417676" y="69.880754" xlink:href="#g3-51"/>
<use x="217.441262" y="69.880754" xlink:href="#g3-33"/>
<rect x="210.417676" y="75.712599" height=".573822" width="10.925551"/>
<use x="210.417676" y="89.426826" xlink:href="#g3-49"/>
<use x="217.441262" y="89.426826" xlink:href="#g3-33"/>
<use x="225.726738" y="79.586059" xlink:href="#g3-43"/>
<use x="241.035825" y="69.880754" xlink:href="#g3-51"/>
<use x="248.05941" y="69.880754" xlink:href="#g3-33"/>
<rect x="241.035825" y="75.712599" height=".573822" width="10.925551"/>
<use x="241.035825" y="89.426826" xlink:href="#g3-48"/>
<use x="248.05941" y="89.426826" xlink:href="#g3-33"/>
<use x="257.141885" y="79.586059" xlink:href="#g3-61"/>
<use x="272.052458" y="79.586059" xlink:href="#g3-49"/>
<use x="282.264039" y="79.586059" xlink:href="#g3-43"/>
<use x="296.377613" y="79.586059" xlink:href="#g3-51"/>
<use x="306.589194" y="79.586059" xlink:href="#g3-43"/>
<use x="320.702767" y="79.586059" xlink:href="#g3-54"/>
<use x="330.914349" y="79.586059" xlink:href="#g3-43"/>
<use x="345.027922" y="79.586059" xlink:href="#g3-54"/>
<use x="356.036503" y="79.586059" xlink:href="#g3-61"/>
<use x="370.947075" y="79.586059" xlink:href="#g3-49"/>
<use x="377.970661" y="79.586059" xlink:href="#g3-54"/>
<use x="384.994246" y="79.586059" xlink:href="#g2-58"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

7
jekyll_site/robots.txt Normal file
View file

@ -0,0 +1,7 @@
User-agent: *
Disallow: *404*
Sitemap: https://pomodoro2.mircloud.ru/pagesmap.xml
Sitemap: https://pomodoro2.mircloud.ru/color/pagesmap.xml
Host: https://pomodoro2.mircloud.ru

View file

@ -0,0 +1,212 @@
---
title: Декартово произведение множеств
description: Рассмотрим алгоритм получения декартова произведения нескольких множеств с использованием трёх вложенных циклов. Количество множеств и их элементов может...
sections: [Комбинаторика,Прямое произведение]
tags: [java,комбинаторика,алгоритмы,декартово произведение,комбинации,множество,список,массив,циклы,вложенные циклы]
canonical_url: /ru/2021/09/06/cartesian-product-of-sets.html
url_translated: /en/2021/09/07/cartesian-product-of-sets.html
title_translated: Cartesian product of sets
date: 2021.09.06
---
Рассмотрим алгоритм получения *декартова произведения* нескольких множеств с использованием
трёх вложенных циклов. Количество множеств и их элементов может быть произвольным. Последовательно
перемножаем множества и накапливаем результат. Порядок значения не имеет, так как от перестановки
множителей произведение не меняется. В результате порядок будет отличаться, но комбинации будут
те же самые.
Для наглядности возьмём несколько *упорядоченных* множеств:
```
a = [A,B,C,D]
b = [E,F,G]
c = [H,I]
d = [J]
```
Количество возможных комбинаций это произведение количеств элементов всех множеств:
```
4 * 3 * 2 * 1 = 24
```
Напишем метод на Java для решения подобных задач, будем использовать три вложенных цикла `for`.
Сначала подготавливаем *список списков* `List<List<T>>`, заполненный одним пустым значением.
Будем использовать его как промежуточный результат и как финальный результат.
Затем обходим переданные списки и последовательно дополняем промежуточный результат
их элементами. На каждом шаге получаем новый промежуточный результат и двигаемся дальше.
Таким образом последовательно перемножаем пары списков и постепенно накапливаем результат.
Схематически этот процесс выглядит следующим образом:
```
result0: [[]]
list1: [A,B,C,D]
--------
result1: [[A],[B],[C],[D]]
list2: [E,F,G]
--------
result2: [[A,E],[A,F],[A,G],[B,E],[B,F],...[D,G]]
list3: [H,I]
--------
result3: [[A,E,H],[A,E,I],[A,F,H],[A,F,I],[A,G,H],...[D,G,I]]
list4: [J]
--------
result4: [[A,E,H,J],[A,E,I,J],[A,F,H,J],[A,F,I,J],[A,G,H,J],...[D,G,I,J]]
```
### Комбинации по столбцам {#combinations-by-columns}
```
Количество комбинаций: 24
[A, E, H, J] [B, E, H, J] [C, E, H, J] [D, E, H, J]
[A, E, I, J] [B, E, I, J] [C, E, I, J] [D, E, I, J]
[A, F, H, J] [B, F, H, J] [C, F, H, J] [D, F, H, J]
[A, F, I, J] [B, F, I, J] [C, F, I, J] [D, F, I, J]
[A, G, H, J] [B, G, H, J] [C, G, H, J] [D, G, H, J]
[A, G, I, J] [B, G, I, J] [C, G, I, J] [D, G, I, J]
```
## Декартово произведение списков {#cartesian-product-of-lists}
Список может содержать *изменяемое количество* элементов. Это упрощает код.
```java
/**
* @param lists произвольное количество списков
* @param <T> тип элементов списков
* @return декартово произведение переданных списков
*/
public static <T> List<List<T>> cartesianProduct(List<List<T>> lists) {
// входящие данные не равны null
if (lists == null) return Collections.emptyList();
// промежуточный результат, содержит одно пустое значение
List<List<T>> cp = Collections.singletonList(Collections.<T>emptyList());
// обходим переданные списки
for (List<T> list : lists) {
// ненулевые и непустые списки
if (list == null || list.size() == 0) continue;
// следующий промежуточный результат
List<List<T>> next = new ArrayList<>();
// строки текущего промежуточного результата
for (List<T> row : cp) {
// элементы текущего списка
for (T el : list) {
// новая строка для следующего промежуточного
// результата, копируем текущую строку
List<T> nRow = new ArrayList<>(row);
// добавляем текущий элемент
nRow.add(el);
// помещаем в следующий промежуточный результат
next.add(nRow);
}
}
// обновляем промежуточный результат
cp = next;
}
// возвращаем итоговый результат
return cp;
}
```
```java
// запускаем программу и выводим результат
public static void main(String[] args) {
// произвольное количество списков и их элементов
List<String> a = Arrays.asList("A", "B", "C", "D");
List<String> b = Arrays.asList("E", "F", "G");
List<String> c = Arrays.asList("H", "I");
List<String> d = Arrays.asList("J");
// декартово произведение
List<List<String>> cp = cartesianProduct(Arrays.asList(a, b, c, d));
// вывод
System.out.println("Количество комбинаций: " + cp.size());
// комбинации по столбцам
int rows = 6;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cp.size(); j++)
if (j % rows == i)
System.out.print(" " + cp.get(j));
System.out.println();
}
}
```
Вывод для этого и следующего кода одинаковый, см. выше: [комбинации по столбцам](#combinations-by-columns).
## Декартово произведение массивов {#cartesian-product-of-arrays}
Массив содержит *фиксированное количество* элементов. Код выглядит немного сложнее.
```java
/**
* @param arrays произвольное количество массивов
* @param clazz класс элементов массивов
* @param <T> тип элементов массивов
* @return декартово произведение переданных массивов
*/
@SuppressWarnings("unchecked")
public static <T> T[][] cartesianProduct(Class<T> clazz, T[]... arrays) {
// входящие данные не равны null
if (clazz == null || arrays == null)
return (T[][]) Array.newInstance(clazz, 0, 0);
// промежуточный результат, содержит одну пустую строку
T[][] cp = (T[][]) Array.newInstance(clazz, 1, 0);
// обходим переданные массивы
for (int a = 0; a < arrays.length; a++) {
// текущий массив
T[] arr = arrays[a];
// ненулевой и непустой массив
if (arr == null || arr.length == 0) continue;
// следующий промежуточный результат, указываем количество строк
T[][] next = (T[][]) Array.newInstance(clazz,cp.length*arr.length,0);
// строки текущего промежуточного результата
for (int r = 0; r < cp.length; r++) {
// текущая строка
T[] row = cp[r];
// элементы текущего массива
for (int e = 0; e < arr.length; e++) {
// текущий элемент
T el = arr[e];
// копируем текущую строку в новый массив [длина + 1]
T[] nRow = Arrays.copyOf(row, row.length + 1);
// добавляем текущий элемент
nRow[row.length] = el;
// помещаем в следующий промежуточный результат
next[r * arr.length + e] = nRow;
}
}
// обновляем промежуточный результат
cp = next;
}
// возвращаем итоговый результат
return cp;
}
```
```java
// запускаем программу и выводим результат
public static void main(String[] args) {
// произвольное количество массивов и их элементов
String[] a = {"A", "B", "C", "D"};
String[] b = {"E", "F", "G"};
String[] c = {"H", "I"};
String[] d = {"J"};
// декартово произведение
String[][] cp = cartesianProduct(String.class, a, b, c, d);
// вывод
System.out.println("Количество комбинаций: " + cp.length);
// комбинации по столбцам
int rows = 6;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cp.length; j++)
if (j % rows == i)
System.out.print(" " + Arrays.toString(cp[j]));
System.out.println();
}
}
```
Вывод для этого и предыдущего кода одинаковый, см. выше: [комбинации по столбцам](#combinations-by-columns).

View file

@ -0,0 +1,70 @@
---
title: Треугольник Паскаля на Java
description: Рассмотрим вариант реализации треугольника Паскаля на Java. Для простоты хранения и обработки данных представим треугольник в виде двухмерного массива...
sections: [Двухмерный массив,Биномиальные коэффициенты]
tags: [java,алгоритмы,массив,двухмерный массив,циклы,вложенные циклы]
canonical_url: /ru/2021/09/09/pascals-triangle-in-java.html
url_translated: /en/2021/09/10/pascals-triangle-in-java.html
title_translated: Pascal's Triangle in Java
date: 2021.09.09
---
Рассмотрим вариант реализации *треугольника Паскаля* на Java. Для простоты хранения и обработки
данных представим треугольник в виде двухмерного массива, в котором элементы первой строки и колонки
равны единице, а все остальные элементы есть сумма двух предыдущих элементов в строке и в колонке.
```
A[i][j] = A[i][j-1] + A[i-1][j];
```
Например, при {`n = 8`} массив будет выглядеть следующим образом:
```
1 1 1 1 1 1 1 1
1 2 3 4 5 6 7
1 3 6 10 15 21
1 4 10 20 35
1 5 15 35
1 6 21
1 7
1
```
Создаём и заполняем двухмерный массив с убывающей длиной строки:
```java
int n = 8;
// массив из 'n' строк
int[][] arr = new int[n][];
// обходим строки массива
for (int i = 0; i < n; i++) {
// строка из 'n-i' элементов
arr[i] = new int[n - i];
// обходим элементы строки
for (int j = 0; j < n - i; j++) {
if (i == 0 || j == 0) {
// элементы первой строки
// и колонки равны единице
arr[i][j] = 1;
} else {
// все остальные элементы есть сумма двух
// предыдущих элементов в строке и в колонке
arr[i][j] = arr[i][j - 1] + arr[i - 1][j];
}
}
}
```
Выводим массив построчно:
```java
// обходим строки массива
for (int[] row : arr) {
// обходим элементы строки
for (int el : row)
// пробел и двузначное число
System.out.printf(" %2d", el);
// переход на новую строку
System.out.println();
}
```

View file

@ -0,0 +1,153 @@
---
title: Комбинации элементов по столбцам
description: В двухмерном массиве данные хранятся построчно. Рассмотрим алгоритм получения декартова произведения по столбцам с использованием трёх вложенных циклов.
sections: [Комбинаторика,Прямое произведение]
tags: [java,комбинаторика,алгоритмы,декартово произведение,комбинации,колонки,множество,список,массив,циклы,вложенные циклы]
canonical_url: /ru/2021/09/13/combinations-by-columns.html
url_translated: /en/2021/09/14/combinations-by-columns.html
title_translated: Combinations of elements by columns
date: 2021.09.13
---
В двухмерном массиве данные хранятся построчно. Рассмотрим алгоритм получения *декартова
произведения* по столбцам с использованием трёх вложенных циклов. Количество строк и
колонок таблицы может быть произвольным. Последовательно перемножаем колонки и накапливаем
результат. Значения необязательно должны быть заполнены нулевые элементы отбрасываем.
Для примера возьмём частично заполненный *зубчатый двухмерный массив*:
```java
| col1 | col2 | col3 | col4
-----|------|------|------|------
row1 | "A1" | "B1" | "C1" | "D1"
row2 | "A2" | "B2" | null | "D2"
row3 | "A3" | null | null | "D3"
row4 | "A4" | null |
```
Количество возможных комбинаций это произведение количеств элементов во всех колонках:
```
4 * 2 * 1 * 3 = 24
```
Напишем метод на Java для решения подобных задач, будем использовать три вложенных цикла `for`.
Сначала подготавливаем *список списков* `List<List<T>>`, заполненный одним пустым значением.
Будем использовать его как промежуточный результат и как финальный результат.
Затем обходим колонки таблицы, пока они ещё есть, последней считаем ту колонку, за которой
все элементы нулевые. На каждом шаге дополняем промежуточный результат элементами текущей
колонки и получаем новый промежуточный результат. Таким образом последовательно перемножаем
колонки и постепенно накапливаем результат.
Схематически этот процесс выглядит следующим образом:
```
res0 * col1 = res1 * col2 = res2 * col3 = res3 * col4 = res4
-----|------|------|------|-------|------|----------|------|------------
[] * A1 = A1 * B1 = A1,B1 * C1 = A1,B1,C1 * D1 = A1,B1,C1,D1
* A2 = A2 * B2 = A1,B2 * = A1,B2,C1 * D2 = A1,B1,C1,D2
* A3 = A3 * = A2,B1 * = A2,B1,C1 * D3 = A1,B1,C1,D3
* A4 = A4 * = A2,B2 * = A2,B2,C1 * = A1,B2,C1,D1
* = * = A3,B1 * = A3,B1,C1 * = A1,B2,C1,D2
* = * = A3,B2 * = A3,B2,C1 * = A1,B2,C1,D3
* = * = A4,B1 * = A4,B1,C1 * = A2,B1,C1,D1
* = * = A4,B2 * = A4,B2,C1 * = A2,B1,C1,D2
* = * = * = * = A2,B1,C1,D3
* = * = * = * = A2,B2,C1,D1
* = * = * = * = ...........
* = * = * = * = ...........
* = * = * = * = A4,B2,C1,D3
-----|------|------|------|-------|------|----------|------|------------
1 * 4 = 4 * 2 = 8 * 1 = 8 * 3 = 24
```
### Комбинации по столбцам {#combinations-by-columns}
```
Количество комбинаций: 24
[A1, B1, C1, D1] [A2, B1, C1, D1] [A3, B1, C1, D1] [A4, B1, C1, D1]
[A1, B1, C1, D2] [A2, B1, C1, D2] [A3, B1, C1, D2] [A4, B1, C1, D2]
[A1, B1, C1, D3] [A2, B1, C1, D3] [A3, B1, C1, D3] [A4, B1, C1, D3]
[A1, B2, C1, D1] [A2, B2, C1, D1] [A3, B2, C1, D1] [A4, B2, C1, D1]
[A1, B2, C1, D2] [A2, B2, C1, D2] [A3, B2, C1, D2] [A4, B2, C1, D2]
[A1, B2, C1, D3] [A2, B2, C1, D3] [A3, B2, C1, D3] [A4, B2, C1, D3]
```
## Декартово произведение по столбцам {#cartesian-product-by-columns}
Код будет выглядеть проще, если предварительно *транспонировать* массив массивов, но если этого
нельзя сделать, тогда во внешнем цикле обходим колонки массива до тех пор, пока они ещё есть.
```java
/**
* @param table двухмерный список
* @param <T> тип элементов списка
* @return декартово произведение элементов по столбцам
*/
public static <T> List<List<T>> cartesianProduct(List<List<T>> table) {
// входящие данные не равны null
if (table == null) return Collections.emptyList();
// промежуточный результат, содержит одно пустое значение
List<List<T>> cp = Collections.singletonList(Collections.<T>emptyList());
// колонки ещё есть
boolean notLast = true;
// обходим колонки таблицы, пока они ещё есть
for (int i = 0; notLast; i++) {
// колонок больше нет
notLast = false;
// следующий промежуточный результат
List<List<T>> next = new ArrayList<>();
// обходим комбинации текущего промежуточного результата
for (List<T> comb : cp) {
// обходим строки таблицы
for (List<T> row : table) {
// если колонка ещё есть и значение в ней тоже есть
if (row != null && i < row.size() && row.get(i) != null) {
// новая комбинация, копируем текущую комбинацию
List<T> nComb = new ArrayList<>(comb);
// добавляем значение из колонки
nComb.add(row.get(i));
// помещаем в новый промежуточный результат
next.add(nComb);
// колонки ещё есть
notLast = true;
}
}
}
// если колонки ещё есть, то обновляем промежуточный результат
// и переходим на следующую итерацию, иначе выходим из цикла
if (notLast) cp = next;
}
// возвращаем итоговый результат
return cp;
}
```
```java
// запускаем программу и выводим результат
public static void main(String[] args) {
// произвольное количество строк и их элементов
List<String> row1 = Arrays.asList("A1", "B1", "C1", "D1");
List<String> row2 = Arrays.asList("A2", "B2", null, "D2");
List<String> row3 = Arrays.asList("A3", null, null, "D3");
List<String> row4 = Arrays.asList("A4", null);
// зубчатый двухмерный список
List<List<String>> table = Arrays.asList(row1, row2, row3, row4);
// декартово произведение
List<List<String>> cp = cartesianProduct(table);
// вывод
System.out.println("Количество комбинаций: " + cp.size());
// комбинации по столбцам
int rows = 6;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cp.size(); j++)
if (j % rows == i)
System.out.print(" " + cp.get(j));
System.out.println();
}
}
```
Вывод для этого кода см. выше: [комбинации по столбцам](#combinations-by-columns).

View file

@ -0,0 +1,235 @@
---
title: Комбинации элементов последовательности
description: Рассмотрим задачу, в которой нужно получить все возможные комбинации элементов последовательности, где количество элементов в комбинации не превышает...
sections: [Комбинаторика,Размещения,Перестановки]
tags: [java,комбинаторика,алгоритмы,размещения,перестановки,комбинации,последовательность,множество,список,циклы,вложенные циклы]
canonical_url: /ru/2021/09/20/combinations-of-sequence-elements.html
url_translated: /en/2021/09/22/combinations-of-sequence-elements.html
title_translated: Combinations of sequence elements
date: 2021.09.20
---
Рассмотрим задачу, в которой нужно получить все возможные комбинации элементов последовательности,
где количество элементов в комбинации не превышает заданного максимума, и напишем метод на Java
с соответствующим отбором по минимальному и максимальному количеству элементов.
*[Задача о сервировке стола](#table-setting-problem) [Метод для решения на Java](#combinations-of-length)*
*Размещением* называется упорядоченный набор {`k`} различных элементов из множества различных
{`n`} элементов, где {<code>k&nbsp;&le;&nbsp;n</code>}. Если {<code>k&nbsp;=&nbsp;n</code>}, то
такой упорядоченный набор называется *перестановкой*. Для универсальности решения *перестановки*
тоже будем учитывать как частный случай *размещения*.
## Количество возможных комбинаций {#number-of-possible-combinations}
Для наглядности возьмём последовательность из трёх элементов {`XYZ`}, нарисуем все возможные
подмножества этого множества, добавим к ним перестановки и подсчитаем количество комбинаций.
{% include picture.html src="/img/arrangements-quantity.gif" size100=true background=true
alt="Получаем количество всех возможных размещений элементов последовательности"
caption="Получаем количество всех возможных размещений элементов последовательности" %}
Формула количества размещений:
{% include image_svg.html src="/img/arrangement-formula.svg" style="width: 83pt; height: 46pt;"
alt="\sum_{k=0}^{n} {n! \over (n-k)!}" %}
Последовательность из трёх элементов:
{% include image_svg.html src="/img/three-elements-sequence.svg" style="width: 375pt; height: 48pt;"
alt="\sum_{k=0}^{3} {3! \over (3-k)!} = {3! \over 3!} + {3! \over 2!} + {3! \over 1!} + {3! \over 0!} = 1+3+6+6 = 16." %}
Способ реализации на Java:
```java
public static void main(String[] args) {
// количество элементов последовательности
int n = 3;
// количество возможных комбинаций
int sum = 0;
// обходим возможные количества элементов
for (int k = 0; k <= n; k++)
// складываем количества размещений
sum += factorial(n) / factorial(n - k);
// вывод
System.out.println(sum); // 16
}
// получаем факториал числа
static int factorial(int n) {
int fact = 1;
for (int i = 2; i <= n; i++)
fact *= i;
return fact;
}
```
## Комбинации из трёх элементов {#combinations-of-elements}
Сравним две последовательности из трёх элементов: цифр {`123`} и букв {`XYZ`}. Тип элементов
разный комбинации одинаковые, потому что порядковые номера у элементов те же самые.
```
Количество вариантов: 16
[][1][2][3][12][13][21][23][31][32][123][132][213][231][312][321]
[][X][Y][Z][XY][XZ][YX][YZ][ZX][ZY][XYZ][XZY][YXZ][YZX][ZXY][ZYX]
```
Сравним последовательности из [`1..12`] элементов: количество вариантов быстро растёт
и вскоре выходит за пределы `Integer`, далее при {<code>n&nbsp;&gt;&nbsp;12</code>} нужно
будет использовать `Long`, а при {<code>n&nbsp;&gt;&nbsp;20</code>} уже `BigInteger`.
```
n Кол-во вариантов
1 2
2 5
3 16
4 65
5 326
6 1957
7 13700
8 109601
9 986410
10 9864101
11 108505112
12 1302061345
```
Рассмотрим задачу, где нужно ограничить возможные варианты
по максимальному количеству входящих в них элементов.
## Задача о сервировке стола {#table-setting-problem}
На ужин приглашено четверо гостей {<code>n&nbsp;=&nbsp;4</code>}, из которых известно, что
приедут не более двух человек {<code>k&nbsp;=&nbsp;2</code>}, причём порядок их появления
важен, поскольку от этого зависит сервировка стола. Известно также, что когда приедет первый,
то он скажет, кто будет второй и приедет ли он. Рассчитать возможные варианты сервировки стола.
### Способ решения {#solution-approach}
Напишем метод на Java для решения подобных задач, который будет принимать на вход три параметра:
размер последовательности, минимальное и максимальное количество элементов в комбинации.
Возвращать метод будет список комбинаций указанной длины.
```java
static List<Set<Integer>> combinationsOfElements(int size, int min, int max)
```
Вызываем метод с отбором {<code>min=0;&nbsp;max=2</code>}
и получаем список комбинаций указанной длины.
```java
// задача о сервировке стола
public static void main(String[] args) {
// приглашено четверо гостей
int[] arr = {1, 2, 3, 4};
// n - количество элементов последовательности
// k - максимальное количество элементов в комбинации
int n = 4, k = 2;
// комбинации элементов указанной длины [0..2]
List<Set<Integer>> list = combinationsOfElements(n, 0, k);
// вывод
System.out.println("Количество вариантов: " + list.size());
for (Set<Integer> set : list) {
System.out.print("[");
for (int i : set)
System.out.print(arr[i]);
System.out.print("]");
}
}
```
Вывод:
```
Количество вариантов: 17
[][1][2][3][4][12][13][14][21][23][24][31][32][34][41][42][43]
```
## Комбинации элементов указанной длины {#combinations-of-length}
Пишем метод на Java с использованием трёх вложенных циклов `for`. Далее для проверки вызываем
этот метод без отбора {<code>min=0;&nbsp;max=size</code>} и получаем все возможные комбинации.
Для примера возьмём две последовательности из трёх элементов: цифр {`123`} и букв {`XYZ`}.
### Описание метода {#method-description}
Подготавливаем два списка комбинаций: результирующий список и текущий список. В текущем списке
количество элементов во всех комбинациях будет одинаковым. Максимальное количество элементов
в комбинации это размер последовательности. Начинаем с одной пустой комбинации и постепенно
увеличиваем количество элементов.
Обходим возможные количества элементов и дополняем текущие комбинации теми индексами, которых
в них ещё нет. На каждом шаге увеличиваем текущее количество элементов в комбинациях на единицу
и, если оно попадает в отбор, тогда добавляем эти комбинации к результату.
```java
/**
* @param size размер последовательности (0 min max size)
* @param min минимальное количество элементов в комбинации
* @param max максимальное количество элементов в комбинации
* @return комбинации элементов указанной длины
*/
static List<Set<Integer>> combinationsOfElements(int size, int min, int max) {
// некорректные входящие данные, возвращаем пустой список комбинаций
if (0 > min || min > max || max > size) return Collections.emptyList();
// результирующий список комбинаций
List<Set<Integer>> result = new ArrayList<>();
// текущий список комбинаций, количество элементов во всех
// комбинациях одинаковое, начинаем с одной пустой комбинации
List<Set<Integer>> sublist = Arrays.asList(Collections.<Integer>emptySet());
// обходим возможные количества элементов в комбинации
for (int l = 0; l < Math.min(size, max); l++) {
// если текущее количество элементов входит в отбор,
// тогда добавляем эти комбинации к результату
if (l >= min) result.addAll(sublist);
// следующий список комбинаций
List<Set<Integer>> nSublist = new ArrayList<>();
// обходим текущий список комбинаций
for (Set<Integer> comb : sublist) {
// обходим индексы элементов последовательности
for (int i = 0; i < size; i++) {
// пропускаем те индексы, которые уже есть
if (comb.contains(i)) continue;
// новая комбинация, копируем текущую
Set<Integer> nComb = new LinkedHashSet<>(comb);
// добавляем текущий индекс
nComb.add(i);
// помещаем в новый список комбинаций
nSublist.add(nComb);
}
}
// обновляем текущий список комбинаций
sublist = nSublist;
}
// добавляем текущий список комбинаций к результату
result.addAll(sublist);
// возвращаем результат
return result;
}
```
```java
// запускаем программу и выводим результат
public static void main(String[] args) {
// две последовательности из трёх элементов
Integer[] arr1 = {1, 2, 3};
String[] arr2 = {"X", "Y", "Z"};
// количество элементов последовательности
int n = 3;
// все возможные комбинации элементов [0..n]
List<Set<Integer>> list = combinationsOfElements(n, 0, n);
// вывод
System.out.println("Количество вариантов: " + list.size());
for (Object[] arr : Arrays.asList(arr1, arr2)) {
StringBuilder sb = new StringBuilder();
for (Set<Integer> set : list) {
sb.append("[");
for (int i : set) sb.append(arr[i]);
sb.append("]");
}
System.out.println(sb);
}
}
```
Вывод для этого кода см. выше: [комбинации из трёх элементов](#combinations-of-elements).

View file

@ -0,0 +1,173 @@
---
title: Декартово произведение в параллельных потоках
description: Рассмотрим алгоритм получения декартова произведения с помощью потоков Java Stream. Это решение похоже на три вложенных цикла for с тем отличием, что...
sections: [Многопоточность,Комбинаторика,Прямое произведение]
tags: [java,многопоточность,комбинаторика,алгоритмы,декартово произведение]
canonical_url: /ru/2021/10/04/cartesian-product-parallel-streams.html
url_translated: /en/2021/10/05/cartesian-product-parallel-streams.html
title_translated: Cartesian product in parallel streams
date: 2021.10.04
---
Рассмотрим алгоритм получения *декартова произведения* с помощью потоков Java Stream. Это решение
похоже на три вложенных цикла `for` с тем отличием, что здесь внешний цикл заменён на поток для
удобства последующего распараллеливания. Будем использовать метод `reduce` с тремя параметрами:
`identity`, `accumulator` и `combiner`.
*Алгоритм с тремя вложенными циклами:
[Декартово произведение множеств]({{ '/ru/2021/09/06/cartesian-product-of-sets.html' | relative_url }}).*
Входящие данные это произвольное количество списков и их элементов.
```
a = [A1,B1,C1,D1]
b = [A2,B2,C2]
c = [A3,B3]
d = [A4]
```
Количество возможных комбинаций это произведение количеств элементов всех списков:
```
4 * 3 * 2 * 1 = 24
```
Получаем *поток списков* `Stream<List<T>>` из входящих данных и вызываем метод `reduce`:
{% capture md_list_into_div %}
- `identity` сущность. В нашем случае это *список списков* `List<List<T>>`,
заполненный одним пустым значением. Будем использовать его как промежуточный
результат и как финальный результат.
- `accumulator` накопитель. Для каждого шага *редукции* описываем метод с двумя
параметрами: промежуточный результат и текущий список. Дополняем промежуточный
результат значениями из текущего списка.
- `combiner` объединитель. Используется в многопоточном режиме, объединяем
результаты работы потоков, получаем *декартово произведение* результатов.
{% endcapture %}
<div>
{{- md_list_into_div | markdownify -}}
</div>
Пошагово процесс накопления *декартова произведения* выглядит следующим образом:
```
result0: [[]]
list1: [A1,B1,C1,D1]
--------
result1: [[A1],[B1],[C1],[D1]]
list2: [A2,B2,C2]
--------
result2: [[A1,A2],[A1,B2],[A1,C2],[B1,A2],[B1,B2],...[D1,C2]]
list3: [A3,B3]
--------
result3: [[A1,A2,A3],[A1,A2,B3],[A1,B2,A3],[A1,B2,B3],[A1,C2,A3],...[D1,C2,B3]]
list4: [A4]
--------
result4: [[A1,A2,A3,A4],[A1,A2,B3,A4],[A1,B2,A3,A4],[A1,B2,B3,A4],...[D1,C2,B3,A4]]
```
### Комбинации по столбцам {#combinations-by-columns}
```
Количество комбинаций: 24
[A1, A2, A3, A4] [B1, A2, A3, A4] [C1, A2, A3, A4] [D1, A2, A3, A4]
[A1, A2, B3, A4] [B1, A2, B3, A4] [C1, A2, B3, A4] [D1, A2, B3, A4]
[A1, B2, A3, A4] [B1, B2, A3, A4] [C1, B2, A3, A4] [D1, B2, A3, A4]
[A1, B2, B3, A4] [B1, B2, B3, A4] [C1, B2, B3, A4] [D1, B2, B3, A4]
[A1, C2, A3, A4] [B1, C2, A3, A4] [C1, C2, A3, A4] [D1, C2, A3, A4]
[A1, C2, B3, A4] [B1, C2, B3, A4] [C1, C2, B3, A4] [D1, C2, B3, A4]
```
## Комбинации элементов в параллельных потоках {#combinations-of-elements-in-parallel-streams}
В параллельном режиме скорость работы алгоритма увеличивается при перемножении *большого количества
маленьких списков*, например 20 списков по 2 элемента или 15 списков по 3 элемента. Время вычислений
уменьшается в *полтора-два* раза. В остальных случаях время работы примерно такое же, как у трёх
вложенных циклов `for`.
```java
/**
* @param lists произвольное количество списков
* @param <T> тип элементов списков
* @return декартово произведение переданных списков
*/
public static <T> List<List<T>> cartesianProduct(List<List<T>> lists) {
// входящие данные не равны null
if (lists == null) return Collections.emptyList();
// поток списков Stream<List<T>>
return lists.stream()
// включаем параллельный режим
.parallel()
// отбрасываем нулевые и пустые списки
.filter(list -> list != null && list.size() > 0)
// сводим поток списков в один список, получаем декартово произведение
// reduce(identity, accumulator, combiner)
.reduce( // промежуточный результат, содержит одно пустое значение
Collections.singletonList(Collections.emptyList()),
// обходим переданные списки и дополняем промежуточный результат их
// элементами, на каждом шаге получаем новый промежуточный результат
(result, list) -> {
// следующий промежуточный результат
List<List<T>> nResult = new ArrayList<>(result.size() * list.size());
// строки текущего промежуточного результата
for (List<T> row : result) {
// элементы текущего списка
for (T el : list) {
// новая строка для следующего промежуточного результата
List<T> nRow = new ArrayList<>(row.size() + 1);
// добавляем текущую строку
nRow.addAll(row);
// добавляем текущий элемент
nRow.add(el);
// помещаем в следующий промежуточный результат
nResult.add(nRow);
}
}
// передаём на следующую итерацию
return nResult;
},
// используется в многопоточном режиме, объединяем результаты
// работы потоков, получаем декартово произведение результатов
(result1, result2) -> {
// объединённый результат
List<List<T>> result = new ArrayList<>(result1.size() * result2.size());
// обходим результаты
for (List<T> comb1 : result1) {
for (List<T> comb2 : result2) {
// складываем комбинации
List<T> comb = new ArrayList<>(comb1.size() + comb2.size());
comb.addAll(comb1);
comb.addAll(comb2);
result.add(comb);
}
}
return result;
});
}
```
```java
// запускаем программу и выводим результат
public static void main(String[] args) {
// произвольное количество списков и их элементов
List<String> a = Arrays.asList("A1", "B1", "C1", "D1");
List<String> b = Arrays.asList("A2", "B2", "C2");
List<String> c = Arrays.asList("A3", "B3");
List<String> d = Collections.singletonList("A4");
// декартово произведение
List<List<String>> cp = cartesianProduct(Arrays.asList(a, b, c, d));
// вывод
System.out.println("Количество комбинаций: " + cp.size());
// комбинации по столбцам
int rows = 6;
IntStream.range(0, rows).forEach(i -> System.out.println(
IntStream.range(0, cp.size())
.filter(j -> j % rows == i)
.mapToObj(j -> cp.get(j).toString())
.collect(Collectors.joining(" "))));
}
```
Вывод для этого кода см. выше: [комбинации по столбцам](#combinations-by-columns).

61
jekyll_site/ru/index.md Normal file
View file

@ -0,0 +1,61 @@
---
title: Код с комментариями
description: Заметки на тему программирования с примерами кода и комментариями. Решения задач и описания решений.
sections: [Решения задач и описания решений]
tags: [java,комбинаторика,алгоритмы,реализация,множества,подмножества,списки,массивы,циклы,вложенные циклы]
canonical_url: /
url_translated: /en/
title_translated: Code with comments
---
{%- assign articles = "" | split: "" %}
{%- assign articles = articles | push: "Декартово произведение в параллельных потоках" %}
{%- capture article_brief %}
Рассмотрим алгоритм получения *декартова произведения* с помощью потоков Java Stream. Это решение
похоже на три вложенных цикла `for` с тем отличием, что здесь внешний цикл заменён на поток для
удобства последующего распараллеливания. Будем использовать метод `reduce` с тремя параметрами:
`identity`, `accumulator` и `combiner`.
В параллельном режиме скорость работы алгоритма увеличивается при перемножении *большого количества
маленьких списков*, например 20 списков по 2 элемента или 15 списков по 3 элемента. Время вычислений
уменьшается в *полтора-два* раза. В остальных случаях время работы примерно такое же, как у трёх
вложенных циклов `for`.
{%- endcapture %}
{%- assign articles = articles | push: article_brief %}
{%- assign articles = articles | push: "Комбинации элементов последовательности" %}
{%- capture article_brief %}
Рассмотрим задачу, в которой нужно получить все возможные комбинации элементов последовательности,
где количество элементов в комбинации не превышает заданного максимума, и напишем метод на Java
с соответствующим отбором по минимальному и максимальному количеству элементов.
*Размещением* называется упорядоченный набор {`k`} различных элементов из множества различных
{`n`} элементов, где {<code>k&nbsp;&le;&nbsp;n</code>}. Если {<code>k&nbsp;=&nbsp;n</code>}, то
такой упорядоченный набор называется *перестановкой*. Для универсальности решения *перестановки*
тоже будем учитывать как частный случай *размещения*.
{%- endcapture %}
{%- assign articles = articles | push: article_brief %}
{%- assign articles = articles | push: "Комбинации элементов по столбцам" %}
{%- capture article_brief %}
В двухмерном массиве данные хранятся построчно. Рассмотрим алгоритм получения *декартова
произведения* по столбцам с использованием трёх вложенных циклов. Количество строк и
колонок таблицы может быть произвольным. Последовательно перемножаем колонки и накапливаем
результат. Значения необязательно должны быть заполнены нулевые элементы отбрасываем.
{%- endcapture %}
{%- assign articles = articles | push: article_brief %}
{%- assign articles = articles | push: "Треугольник Паскаля на Java" %}
{%- capture article_brief %}
Рассмотрим вариант реализации *треугольника Паскаля* на Java. Для простоты хранения и обработки
данных представим треугольник в виде двухмерного массива, в котором элементы первой строки и колонки
равны единице, а все остальные элементы есть сумма двух предыдущих элементов в строке и в колонке.
{%- endcapture %}
{%- assign articles = articles | push: article_brief %}
{%- assign articles = articles | push: "Декартово произведение множеств" %}
{%- capture article_brief %}
Рассмотрим алгоритм получения *декартова произведения* нескольких множеств с использованием
трёх вложенных циклов. Количество множеств и их элементов может быть произвольным. Последовательно
перемножаем множества и накапливаем результат. Порядок значения не имеет, так как от перестановки
множителей произведение не меняется. В результате порядок будет отличаться, но комбинации будут
те же самые.
{%- endcapture %}
{%- assign articles = articles | push: article_brief %}
{%- include main_page.html articles = articles -%}

5
package.sh Executable file
View file

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

4
serve.sh Executable file
View file

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