2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Разбиения ко-лексикографически без рекурсии (PARI/GP)
Сообщение29.03.2024, 09:40 
Аватара пользователя


22/11/13
02/04/25
549
Многие из вас, вероятно, знакомы с разбиениями, а также с вариантами, в которых они могут быть представлены (имеется ввиду лексикографический порядок и его вариации).

Ниже представлены несколько разбиений в ко-лексикографическом порядке:

$\begin{bmatrix}
1
\end{bmatrix}$

$\begin{bmatrix}
1 & 1 \\
2 
\end{bmatrix}$

$\begin{bmatrix}
1 & 1  & 1\\
2 & 1 \\
3 
\end{bmatrix}$

$\begin{bmatrix}
1 & 1 & 1 & 1\\
2 & 1 & 1 \\
3 & 1 \\
2 & 2 \\
4 
\end{bmatrix}$

$\begin{bmatrix}
1 & 1 & 1 & 1 & 1 \\
2 & 1 & 1 & 1 \\
3 & 1 & 1 \\
2 & 2 & 1 \\
4 & 1 \\
3 & 2 \\
5
\end{bmatrix}$

Здесь прослеживается интересный паттерн. Мы можем взять лишь
$$\begin{bmatrix}
1 \\
2 \\
3 \\
2 & 2 \\
4 \\
3 & 2 \\
5
\end{bmatrix}$$

как основную последовательность разбиений, после чего брать первые $k_n$ разбиений (где $k_n$ это число разбиений $n$) и наращивать в конце последовательность из единиц, которых у нас будет $n$ минус сумма всех частей выбранного разбиения.

Идея не нова и была представлена в последовательности A210941 еще в далеком 2012.

Мне стало интересно, как генерировать члены последовательности этих разбиений без рекурсии. Вот что у меня получилось:

Код:
\\ Основная функция это list(vec).
\\ Входные данные это массив индексов k.
\\ Выходные данные это массив соответствующих разбиений.
\\ Здесь b4(k) вычисляется без рекурсии.
\\ Так что, эта программа хороша, когда вам нужно вычислить небольшое число разбиений.
\\ В особенности для значительно больших k.

b1(n) = {my(A = 1, B, v1); v1 = [1];
until(v1[A]>n, v1 = concat(v1, 0); B = 1;
while((binomial(B+1, 2) - binomial(B\2+1, 2)) <= A,
v1[A+1] += (-1)^((B-1)\2)*v1[A - binomial(B+1, 2) + binomial(B\2+1, 2) + 1]; B++); A++);
A-1}
list(vec) = {my(b2(n) = my(v1);
v1 = vector(n, i, vector(i\2+1, j, i==1));
for(i = 2, n, v1[i][i\2+1] = 1; v1[i][1] = vecsum(v1[i-1]);
for(j = 2, i\2, v1[i][j] = v1[i-1][j-1] - if((i-j) >= 2*(j-1), v1[i-j][j-1])));
for(i = 2, n, forstep(j = i\2, 1, -1, v1[i][j] += v1[i][j+1]));
v1,
vv1 = b2(b1(vecmax(vec))),
b3(n) = my(A = 0); until(vv1[A][1] > n, A++); A-1,
b4(n) = my(A = b3(n),
n = if(n == vv1[A][1], n, vv1[A][1] + vv1[A+1][1] - n),
B = n - vv1[A][1], C, v1);
v1 = []; while(!(B == 0), C = 1;
until(vv1[A+1][C]<=B, C++); v1 = concat(v1, C-1);
n -= vv1[A][1] - vv1[A - C + 1][1] + vv1[A+1][C];
A = b3(n); B = n - vv1[A][1]); v1 = Vecrev(v1);
v1 = concat(A + (#v1 > 0), v1));
vec = vector(#vec, i, b4(vec[i]))}


Мне бы хотелось как-то оценить скорость работы этого алгоритма. Для этого, его желательно с чем-нибудь сравнить. Интересуют алгоритмы без рекурсии.

Если интересует история разработки алгоритма, то буду рад поделиться деталями.

 Профиль  
                  
 
 Re: Разбиения ко-лексикографически без рекурсии (PARI/GP)
Сообщение29.03.2024, 11:39 


05/09/16
12061
kthxbye в сообщении #1634684 писал(а):
Мне бы хотелось как-то оценить скорость работы этого алгоритма.

Много текста, а покажите как вы его запускаете и что получаете.

 Профиль  
                  
 
 Re: Разбиения ко-лексикографически без рекурсии (PARI/GP)
Сообщение29.03.2024, 13:22 
Аватара пользователя


22/11/13
02/04/25
549
wrest в сообщении #1634694 писал(а):
kthxbye в сообщении #1634684 писал(а):
Мне бы хотелось как-то оценить скорость работы этого алгоритма.

Много текста, а покажите как вы его запускаете и что получаете.

Ваша рекомендация кажется мне несколько странной, ну да ладно.

Запускаю например так:
Код:
v1 = list(vector(20, i, i))
for(i=1, 20, print(v1[i]))


Получаю следующее:
Код:
[1]
[2]
[3]
[2, 2]
[4]
[3, 2]
[5]
[2, 2, 2]
[4, 2]
[3, 3]
[6]
[3, 2, 2]
[5, 2]
[4, 3]
[7]
[2, 2, 2, 2]
[4, 2, 2]
[3, 3, 2]
[6, 2]
[5, 3]


Что же мы получили? Мы получили строки треугольника A210941 с индексами от $1$ до $20$ по возрастанию.

Но плюс алгоритма в том, что можно в качестве входных данных задавать значения не по-порядку, а абсолютно любые. Например:
Код:
v1 = list(vector(20, i, 2^i))
for(i=1, 20, print(v1[i]))


Соответственно он выдает следующее:
Код:
[2]
[2, 2]
[2, 2, 2]
[2, 2, 2, 2]
[4, 2, 2, 2]
[4, 3, 3, 2]
[11, 3]
[3, 3, 3, 3, 3, 2]
[5, 3, 3, 3, 2, 2, 2]
[8, 5, 2, 2, 2, 2, 2]
[4, 4, 3, 3, 3, 3, 2, 2, 2]
[17, 8, 2, 2]
[10, 8, 6, 4, 4]
[21, 11, 2, 2]
[8, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2]
[13, 11, 3, 3, 3, 3, 2, 2, 2, 2]
[12, 10, 5, 3, 3, 3, 3, 3, 2, 2, 2]
[14, 10, 9, 9, 6, 2, 2]
[18, 8, 8, 7, 5, 5, 5]
[17, 14, 10, 8, 4, 4, 2, 2]


Это строки треугольника A210941, индексы которых это степени двойки от $1$ до $20$ по возрастанию.

Другой пример:
Код:
v1 = list([100, 27, 99, 91, 63, 176, 2301, 453, 921, 6817])
for(i=1, 10, print(v1[i]))


Соответствующие строки треугольника A210941:
Код:
[7, 6]
[3, 3, 3]
[8, 5]
[11, 2]
[8, 2, 2]
[15]
[10, 7, 3, 3, 3]
[7, 3, 3, 3, 3]
[15, 5, 2]
[9, 8, 7, 7]

 Профиль  
                  
 
 Re: Разбиения ко-лексикографически без рекурсии (PARI/GP)
Сообщение29.03.2024, 15:46 
Заслуженный участник


12/08/10
1677
Если я не ошибся можно из $a_1,\dots,a_k$(включая единицы) получить следующее так:
Если $a_k=a_{k-1}=\dots=a_{k-l+1}$($l$ штук), то
если $l>1$ то следующее $a_1,\dots,a_{k-l+1}+1$ и $a_k(l-1)-1$ единиц на конце.
если $l=1$ и $a_{k-1}=\dots=a_{k-m}$($m$ штук)
то следующее $a_1,\dots,a_{k-m}+1$ и $a_k+a_{k-1}(m-1)-1$ единиц на конце.

 Профиль  
                  
 
 Re: Разбиения ко-лексикографически без рекурсии (PARI/GP)
Сообщение29.03.2024, 18:17 
Заслуженный участник


12/08/10
1677
Вы хотите получить строку по номеру?

 Профиль  
                  
 
 Re: Разбиения ко-лексикографически без рекурсии (PARI/GP)
Сообщение29.03.2024, 19:16 
Аватара пользователя


22/11/13
02/04/25
549
Null в сообщении #1634748 писал(а):
Вы хотите получить строку по номеру?

Именно так. Мой алгоритм с этим успешно справляется, но я не уверен что он работает достаточно быстро.

 Профиль  
                  
 
 Re: Разбиения ко-лексикографически без рекурсии (PARI/GP)
Сообщение01.04.2024, 07:57 
Заслуженный участник


12/08/10
1677
Идея такая(тут с учетом единичных слагемых):
В начале создаем таблицу $a_{i,j}$ - количество способов представить $i$ в виде суммы натуральных невозрастающих слагемых $<j$ - сложность $O(n^2)$
$a_{i,j}=a_{i,j-1}+[i\ge j-1]a_{i-j+1,j}$
$a_{0,j}=1$
$a_{i,1}=0$
$a_{0,1}=1$
Тогда $m$-тый элемент последовательности считается в цикле(Сложность O(n) на самом деле):
Если $a_{n,l+1}\ge m >a_{n,l}$, то первый элемент последовательности - $l$,
и далее переходим к $m:=m-a_{n,l};n=n-l$

У вас написано что-то похожее.
Ускорить можно если научиться считать $a_{i,j}$ быстро.

 Профиль  
                  
 
 Re: Разбиения ко-лексикографически без рекурсии (PARI/GP)
Сообщение01.04.2024, 08:49 


05/09/16
12061
Null в сообщении #1634979 писал(а):
Ускорить можно если научиться считать $a_{i,j}$ быстро.

Тут у меня припасена функция, вычисляющая количество разбиений post1405311.html#p1405311
называется N10_2(n,k)

 Профиль  
                  
 
 Re: Разбиения ко-лексикографически без рекурсии (PARI/GP)
Сообщение01.04.2024, 14:56 
Аватара пользователя


22/11/13
02/04/25
549
wrest в сообщении #1634982 писал(а):
Тут у меня припасена функция, вычисляющая количество разбиений post1405311.html#p1405311
называется N10_2(n,k)

Замечательная функция! А можно ли ее как-нибудь немного переделать? В моем алгоритме используются значения
$$T(n, k) = \sum\limits_{i=k}^{n}R(n,i)$$
где $R(n, k)$ это A026794. Там очень похожая рекурсия.

 Профиль  
                  
 
 Re: Разбиения ко-лексикографически без рекурсии (PARI/GP)
Сообщение01.04.2024, 20:34 


05/09/16
12061
kthxbye в сообщении #1635018 писал(а):
А можно ли ее как-нибудь немного переделать?

Конечно, переделывайте, тем более что я сам взял её из Иртернета.

Я переделать не могу, поскольку традиционно не понимаю чего вы хотите :oops:

 Профиль  
                  
 
 Re: Разбиения ко-лексикографически без рекурсии (PARI/GP)
Сообщение01.04.2024, 22:15 


05/09/16
12061
kthxbye в сообщении #1635018 писал(а):
где $R(n, k)$ это A026794
.

Это я могу написать,
R(n,k)=if(n==k,1,if(k*2>n,0,#partitions(n-k,[k,n-k])))
kthxbye в сообщении #1635018 писал(а):
В моем алгоритме используются значения
$$T(n, k) = \sum\limits_{i=k}^{n}R(n,i)$$

А, ну и это:
T(n,k)=sum(x=k,n,if(n==k,1,if(k*2>n,0,#partitions(n-k,[k,n-k]))))

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 11 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group