Back to PublicationsВернуться к публикациям

Source Code & ExamplesИсходный код и примеры

PUBLICATION 02: Telescoping Ramanujan Identities and Massive Decompositions of Cubes into Sums of CubesТелескопические тождества Рамануджана и массивные разложения кубов в суммы кубов
1. Exact Cube Decomposition Generator1. Генератор точного разложения кубов
This script (fincube_master.py) generates the exact decomposition of a single cube into a series of cubes. You can run the script with a parameter k = 2, 3, ... . For example, executing the command for k = 4 will produce the massive sequence shown below.Этот скрипт (fincube_master.py) генерирует точное разложение одного куба в серию кубов. Вы можете запустить скрипт с параметром k = 2, 3, ... . Например, выполнение команды для k = 4 создаст массивную последовательность, показанную ниже.Этот скрипт (fincube_master.py) генерирует точное разложение одного куба в серию кубов. Вы можете запустить скрипт с параметром k = 2, 3, ... . Например, выполнение команды для k = 4 создаст массивную последовательность, показанную ниже.
fincube_master.py
#!/usr/bin/env python3
"""
fincube_master - Deterministic decomposition of a cube into a sum of cubes.
Combines the mathematical generator (fincube_ultimate) with the verification 
and string generation logic (fincube), producing neatly wrapped output.
"""
import math
import sys

def fincube_ultimate(k):
    """
    Generates the exact parameters (INCUBE, EULER, BAZA, dlts) 
    from the initial root 'k' using the telescoping Ramanujan polynomials.
    """
    a = k
    a3 = a**3
    a6 = a**6

    def Y(b): return 2*a6 - 3*a3*(1 + 2*b) + 1 + 3*b + 3*b**2
    def Z(b): return a6 - 1 - 3*b - 3*b**2
    def W(b): return a**7 - 3*a**4*b + a*(3*b**2 - 1)

    D_max = 9*(2*a3 - 1)**2 - 12*(2*a6 - 3*a3 + 1)
    b_max = math.floor((3*(2*a3 - 1) - math.sqrt(D_max)) / 6)
    while Y(b_max + 1) > 0: b_max += 1
    while Y(b_max) <= 0: b_max -= 1

    larr = []
    for b in range(b_max, -1, -1):
        larr.append(min(Y(b), Z(b)))
        
    for b in range(b_max, -1, -1):
        larr.append(max(Y(b), Z(b)))
        
    larr.append(W(b_max + 1))
    
    l1 = [larr[i+1] - larr[i] for i in range(len(larr)-1)]
    dlts = []
    n1 = l1[0]
    delta = l1[1] - l1[0]
    count = 1
    for i in range(1, len(l1)-1):
        d = l1[i+1] - l1[i]
        if d == delta:
            count += 1
        else:
            dlts.append([n1, count, delta])
            n1 = l1[i]
            delta = d
            count = 1
    dlts.append([n1, count, delta])

    # The original array 'larr' has len(larr) elements.
    # The array of differences 'l1' has len(larr) - 1 elements.
    # Therefore, the sum of 'count's in dlts will be exactly len(larr) - 1.
    # So the total number of terms is sum(counts) + 1.

    INCUBE = W(0)
    EULER = [Z(0), Y(0), W(1)]
    BAZA = larr[0]
    
    return INCUBE, EULER, BAZA, dlts

def wrap_text(text, max_len=80):
    """
    Wraps text to max_len. Ensures that lines broken in the decomposition
    always start with a '+' sign.
    """
    lines = []
    # Find the main equation part (e.g. "X^3 = A^3 + B^3 + C^3 = Val = ")
    eq_idx = text.find('= ', text.find(' = ') + 3) # Find the last '=' before the sequence
    if eq_idx != -1:
        start_part = text[:eq_idx + 2]
        rest_part = text[eq_idx + 2:]
    else:
        start_part = ""
        rest_part = text

    # Wrap the starting text normally if it's very long (unlikely, but safe)
    while len(start_part) > max_len:
        split_idx = start_part.rfind(' ', 0, max_len)
        if split_idx == -1: split_idx = max_len
        lines.append(start_part[:split_idx])
        start_part = start_part[split_idx:].lstrip()
    
    current_line = start_part

    # The rest_part looks like "1^3+2^3+3^3..."
    # We want to split at '+' such that the '+' moves to the next line
    terms = rest_part.split('+')
    
    for i, term in enumerate(terms):
        prefix = "" if i == 0 else "+"
        term_str = prefix + term
        
        if len(current_line) + len(term_str) <= max_len:
            current_line += term_str
        else:
            # Current line is full, push it and start a new one with the term
            # Ensure the term itself fits (cubes shouldn't exceed 80 chars individually)
            if current_line:
                lines.append(current_line)
            current_line = term_str

    if current_line:
        lines.append(current_line)

    return '
'.join(lines)


def fincube(INCUBE, EULER, BAZA, dlts):
    """
    Takes the parameters, generates the decomposition array, verifies the sum,
    and returns the formatted output string.
    """
    BAZA2 = BAZA
    larr = [BAZA2]
    len_dlts = len(dlts)

    for i in range(len_dlts):
        a, b, c = dlts[i][0], dlts[i][1], dlts[i][2]
        for j in range(1, b + 1):
            term = BAZA2 + j * a
            if j > 1:
                term += (j - 1) * j * c // 2
            larr.append(term)
        BAZA2 = larr[-1]

    last_a = dlts[len_dlts - 1][0]
    last_c = dlts[len_dlts - 1][2]
    larr.append(BAZA2 + last_a + last_c)

    larr.sort()

    sum_cubes = sum(x**3 for x in larr)
    incube3 = INCUBE**3

    if sum_cubes != incube3:
        str_out = "The condition is not met: incubus = sum of decomposition! => "
    else:
        str_out = ""

    str_out += f"{INCUBE}^3 = {EULER[0]}^3 + {EULER[1]}^3 + {EULER[2]}^3 = {incube3} = "
    str_out += str(larr[0]) + "^3"
    for i in range(1, len(larr)):
        str_out += "+" + str(larr[i]) + "^3"
        
    return str_out


def run_master(k):
    print(f"Generating decomposition for k = {k}...")
    
    # 1. Calculate parameters algebraically
    INCUBE, EULER, BAZA, dlts = fincube_ultimate(k)
    
    # When counting the exact sequence length produced by the dlts array:
    # the algorithm iterates `sum(b)` times, appending one term each time, and adds one final term.
    # Because 'b' is the 1-th index of each entry (i.e., d[1]), 
    # the total number of terms added to `larr` (which starts with 1 element, BAZA) 
    # is 1 (the initial BAZA) + sum(d[1]) + 1 (the final appended term).
    seq_length = sum(d[1] for d in dlts) + 2
    print(f"Generated parameters. Sequence length will be: {seq_length} terms.")
    
    # 2. Reconstruct decomposition and verify math
    raw_output = fincube(INCUBE, EULER, BAZA, dlts)
    
    # 3. Apply neat line wrapping
    wrapped_output = wrap_text(raw_output, max_len=80)
    
    print("
Result:
" + "="*80)
    print(wrapped_output)
    print("="*80)

if __name__ == "__main__":
    # Run for k=2 as a small test example
    # (You can change this value to 22 or 50)
    if len(sys.argv) > 1:
        k_input = int(sys.argv[1])
    else:
        k_input = 2 # Default
        
    run_master(k_input)
#!/usr/bin/env python3
"""
fincube_master - Детерминированное разложение куба в сумму кубов.
Объединяет математический генератор (fincube_ultimate) с логикой проверки
и генерации строк (fincube), создавая аккуратно отформатированный вывод.
"""
import math
import sys

def fincube_ultimate(k):
    """
    Генерирует точные параметры (INCUBE, EULER, BAZA, dlts)
    из начального корня 'k', используя телескопические полиномы Рамануджана.
    """
    a = k
    a3 = a**3
    a6 = a**6

    def Y(b): return 2*a6 - 3*a3*(1 + 2*b) + 1 + 3*b + 3*b**2
    def Z(b): return a6 - 1 - 3*b - 3*b**2
    def W(b): return a**7 - 3*a**4*b + a*(3*b**2 - 1)

    D_max = 9*(2*a3 - 1)**2 - 12*(2*a6 - 3*a3 + 1)
    b_max = math.floor((3*(2*a3 - 1) - math.sqrt(D_max)) / 6)
    while Y(b_max + 1) > 0: b_max += 1
    while Y(b_max) <= 0: b_max -= 1

    larr = []
    for b in range(b_max, -1, -1):
        larr.append(min(Y(b), Z(b)))
        
    for b in range(b_max, -1, -1):
        larr.append(max(Y(b), Z(b)))
        
    larr.append(W(b_max + 1))
    
    l1 = [larr[i+1] - larr[i] for i in range(len(larr)-1)]
    dlts = []
    n1 = l1[0]
    delta = l1[1] - l1[0]
    count = 1
    for i in range(1, len(l1)-1):
        d = l1[i+1] - l1[i]
        if d == delta:
            count += 1
        else:
            dlts.append([n1, count, delta])
            n1 = l1[i]
            delta = d
            count = 1
    dlts.append([n1, count, delta])

    # Исходный массив 'larr' имеет len(larr) элементов.
    # Массив разностей 'l1' имеет len(larr) - 1 элементов.
    # Следовательно, сумма 'count' в dlts будет ровно len(larr) - 1.
    # Таким образом, общее количество членов равно sum(counts) + 1.

    INCUBE = W(0)
    EULER = [Z(0), Y(0), W(1)]
    BAZA = larr[0]
    
    return INCUBE, EULER, BAZA, dlts

def wrap_text(text, max_len=80):
    """
    Оборачивает текст до max_len. Гарантирует, что строки, разбитые в разложении,
    всегда начинаются со знака '+'.
    """
    lines = []
    # Находим главную часть уравнения (например, "X^3 = A^3 + B^3 + C^3 = Val = ")
    eq_idx = text.find('= ', text.find(' = ') + 3) # Находим последнее '=' перед последовательностью
    if eq_idx != -1:
        start_part = text[:eq_idx + 2]
        rest_part = text[eq_idx + 2:]
    else:
        start_part = ""
        rest_part = text

    # Оборачиваем начальный текст обычным образом, если он очень длинный (маловероятно, но безопасно)
    while len(start_part) > max_len:
        split_idx = start_part.rfind(' ', 0, max_len)
        if split_idx == -1: split_idx = max_len
        lines.append(start_part[:split_idx])
        start_part = start_part[split_idx:].lstrip()
    
    current_line = start_part

    # rest_part выглядит как "1^3+2^3+3^3..."
    # Мы хотим разбить по '+', чтобы '+' переносился на следующую строку
    terms = rest_part.split('+')
    
    for i, term in enumerate(terms):
        prefix = "" if i == 0 else "+"
        term_str = prefix + term
        
        if len(current_line) + len(term_str) <= max_len:
            current_line += term_str
        else:
            # Текущая строка заполнена, добавляем её и начинаем новую с этим членом
            # Убедимся, что сам член помещается (кубы не должны превышать 80 символов индивидуально)
            if current_line:
                lines.append(current_line)
            current_line = term_str

    if current_line:
        lines.append(current_line)

    return '
'.join(lines)


def fincube(INCUBE, EULER, BAZA, dlts):
    """
    Принимает параметры, генерирует массив разложения, проверяет сумму
    и возвращает отформатированную строку вывода.
    """
    BAZA2 = BAZA
    larr = [BAZA2]
    len_dlts = len(dlts)

    for i in range(len_dlts):
        a, b, c = dlts[i][0], dlts[i][1], dlts[i][2]
        for j in range(1, b + 1):
            term = BAZA2 + j * a
            if j > 1:
                term += (j - 1) * j * c // 2
            larr.append(term)
        BAZA2 = larr[-1]

    last_a = dlts[len_dlts - 1][0]
    last_c = dlts[len_dlts - 1][2]
    larr.append(BAZA2 + last_a + last_c)

    larr.sort()

    sum_cubes = sum(x**3 for x in larr)
    incube3 = INCUBE**3

    if sum_cubes != incube3:
        str_out = "Условие не выполнено: incube != сумме разложения! => "
    else:
        str_out = ""

    str_out += f"{INCUBE}^3 = {EULER[0]}^3 + {EULER[1]}^3 + {EULER[2]}^3 = {incube3} = "
    str_out += str(larr[0]) + "^3"
    for i in range(1, len(larr)):
        str_out += "+" + str(larr[i]) + "^3"
        
    return str_out


def run_master(k):
    print(f"Generating decomposition for k = {k}...")
    
    # 1. Считаем параметры алгебраически
    INCUBE, EULER, BAZA, dlts = fincube_ultimate(k)
    
    # При подсчете точной длины последовательности, создаваемой массивом dlts:
    # алгоритм выполняет итерации `sum(b)` раз, добавляя по одному члену каждый раз, и добавляет один последний член.
    # Поскольку 'b' является 1-м индексом каждой записи (т.е. d[1]), 
    # общее количество членов, добавленных в `larr` (который начинается с 1 элемента, BAZA), 
    # равно 1 (начальная BAZA) + sum(d[1]) + 1 (последний добавленный член).
    seq_length = sum(d[1] for d in dlts) + 2
    print(f"Generated parameters. Sequence length will be: {seq_length} terms.")
    
    # 2. Восстанавливаем разложение и проверяем математику
    raw_output = fincube(INCUBE, EULER, BAZA, dlts)
    
    # 3. Делаем аккуратный перенос строк
    wrapped_output = wrap_text(raw_output, max_len=80)
    
    print("
Result:
" + "="*80)
    print(wrapped_output)
    print("="*80)

if __name__ == "__main__":
    # Запускаем для k=2 как небольшого тестового примера
    # (Вы можете изменить это значение на 22 или 50)
    if len(sys.argv) > 1:
        k_input = int(sys.argv[1])
    else:
        k_input = 2 # По умолчанию
        
    run_master(k_input)
Terminal ExecutionВывод терминала
python fincube_master.py 4 > result.txt

Generating decomposition for k = 4...
Generated parameters. Sequence length will be: 55 terms.
Result:
================================================================================
16380^3 = 4095^3 + 8001^3 + 15624^3 = 4394826072000 = 123^3+351^3+585^3+825^3
+1071^3+1323^3+1581^3+1845^3+1989^3+2115^3+2145^3+2295^3+2391^3+2439^3+2577^3
+2673^3+2709^3+2835^3+2955^3+2961^3+3069^3+3177^3+3255^3+3279^3+3375^3+3465^3
+3549^3+3555^3+3627^3+3699^3+3765^3+3825^3+3861^3+3879^3+3927^3+3969^3+4005^3
+4035^3+4059^3+4077^3+4089^3+4095^3+4173^3+4392^3+4491^3+4815^3+5145^3+5481^3
+5823^3+6171^3+6525^3+6885^3+7251^3+7623^3+8001^3
================================================================================
2. Instant Sequence Length Calculator O(1)2. Мгновенный калькулятор длины последовательности O(1)
In addition to generating the full string, it is often useful to simply calculate the total number of cubes in the decomposition. This script (fincube_length_only.py) skips the string generation and computes only the sequence length algebraically. Therefore, it executes instantly, regardless of the input parameter k.В дополнение к генерации полной строки часто полезно просто вычислить общее количество кубов в разложении. Этот скрипт (fincube_length_only.py) пропускает генерацию строки и вычисляет только длину последовательности алгебраически. Поэтому он выполняется мгновенно, независимо от входного параметра k.В дополнение к генерации полной строки часто полезно просто вычислить общее количество кубов в разложении. Этот скрипт (fincube_length_only.py) пропускает генерацию строки и вычисляет только длину последовательности алгебраически. Поэтому он выполняется мгновенно, независимо от входного параметра k.

For example, running it with an enormous value like k = 999,999:Например, запуск с огромным значением, таким как k = 999,999:Например, запуск с огромным значением, таким как k = 999,999:
fincube_length_only.py
#!/usr/bin/env python3
import math
import sys

def get_decomposition_stats(k):
    """
    Computes INCUBE base and sequence length analytically in O(1) time
    without generating the actual arrays.
    """
    a = k
    a3 = a**3
    a6 = a**6

    # Function to check the boundary for b_max
    def Y(b): 
        return 2*a6 - 3*a3*(1 + 2*b) + 1 + 3*b + 3*b**2

    # Analytic calculation of b_max (the largest integer b where Y(b) > 0)
    D_max = 9*(2*a3 - 1)**2 - 12*(2*a6 - 3*a3 + 1)
    
    # We use integer arithmetic or precise floats to avoid precision issues for large k
    # For very large k, float sqrt might lose precision. 
    # We can use integer square root:
    sqrt_D_max = math.isqrt(D_max)
    
    b_max = (3*(2*a3 - 1) - sqrt_D_max) // 6
    
    # Adjust to ensure exact boundary
    while Y(b_max + 1) > 0: 
        b_max += 1
    while Y(b_max) <= 0: 
        b_max -= 1

    # INCUBE is simply W(0) = a^7 - a
    INCUBE = a**7 - a
    
    # The sequence length is algebraically exactly 2 * b_max + 3
    seq_length = 2 * b_max + 3
    
    return INCUBE, seq_length

def run_master(k):
    print(f"Decomposition for k = {k}")
    INCUBE, seq_length = get_decomposition_stats(k)
    print(f"INCUBE base: {INCUBE}")
    print(f"Sequence length will be: {seq_length} terms.")

if __name__ == "__main__":
    if len(sys.argv) > 1:
        k_input = int(sys.argv[1])
    else:
        k_input = 3
        
    run_master(k_input)
#!/usr/bin/env python3
import math
import sys

def get_decomposition_stats(k):
    """
    Вычисляет базу INCUBE и длину последовательности аналитически за время O(1)
    без генерации самих массивов.
    """
    a = k
    a3 = a**3
    a6 = a**6

    # Функция для проверки границы для b_max
    def Y(b): 
        return 2*a6 - 3*a3*(1 + 2*b) + 1 + 3*b + 3*b**2

    # Аналитическое вычисление b_max (наибольшее целое b, при котором Y(b) > 0)
    D_max = 9*(2*a3 - 1)**2 - 12*(2*a6 - 3*a3 + 1)
    
    # Мы используем целочисленную арифметику, чтобы избежать проблем с точностью для больших k
    # Для очень больших k float sqrt может потерять точность. 
    # Мы можем использовать целочисленный квадратный корень:
    sqrt_D_max = math.isqrt(D_max)
    
    b_max = (3*(2*a3 - 1) - sqrt_D_max) // 6
    
    # Корректировка для обеспечения точной границы
    while Y(b_max + 1) > 0: 
        b_max += 1
    while Y(b_max) <= 0: 
        b_max -= 1

    # INCUBE - это просто W(0) = a^7 - a
    INCUBE = a**7 - a
    
    # Длина последовательности алгебраически равна ровно 2 * b_max + 3
    seq_length = 2 * b_max + 3
    
    return INCUBE, seq_length

def run_master(k):
    print(f"Decomposition for k = {k}")
    INCUBE, seq_length = get_decomposition_stats(k)
    print(f"INCUBE base: {INCUBE}")
    print(f"Sequence length will be: {seq_length} terms.")

if __name__ == "__main__":
    if len(sys.argv) > 1:
        k_input = int(sys.argv[1])
    else:
        k_input = 3
        
    run_master(k_input)
Terminal ExecutionВывод терминала
python fincube_length_only.py 999999 > out.txt

--------------------------------------------------
Decomposition for k = 999999
INCUBE base: 999993000020999965000034999979000006000000
Sequence length will be: 845296925724899507 terms.
--------------------------------------------------

# Can you imagine a sequence of 845,296,925,724,899,507 elements?!
# And these are not just elements, but the sum of "cubes"!
# That is 845 quadrillion, 296 trillion, 925 billion, 724 million, 899 thousand, 507 cubes 
# in the decomposition of the cube of 999993000020999965000034999979000006000000!!# Вы можете себе представить последовательность из 845 296 925 724 899 507 элементов?!
# И это не просто элементы, а суммы "кубов"!
# Это 845 квадриллионов, 296 триллионов, 925 миллиардов, 724 миллиона, 899 тысяч, 507 кубов 
# в разложении куба числа 999993000020999965000034999979000006000000!!