Автор: Владимир Миронов
Задача, идея, концепт
Будучи в отпуске, я решил написать небольшой алгоритм и, в целом, поисследовать, как ведет себя множество, которое было сформированно благодаря “гипотезе Коллатца”, к слову напомним ее формулировку: Гипотеза Ко́ллатца — одна из нерешённых проблем математики: верно ли, что последовательность чисел, строящаяся от произвольного натурального , каждое (i + 1) — е число в которой равно
, если
— нечётное, и
, если
— чётное, рано или поздно вырождается в единицу. Такие последовательности называются сиракузскими, а гипотеза иногда фигурирует как под наименованием «сираку́зская проблема». Исходя из этого я написал небольшой алгоритм, который представляет собой итеративный процесс фильтрации элементов множеств на основе отношения принадлежности к объединению последующих множеств в общем наборе созданных по исходной гипотезе. Этот процесс можно интерпретировать как выделение «уникальных» (не наследуемых) членов последовательностей, где каждая последовательность является траекторией согласно гипотезы Коллатца. Например, пусть задано конечное упорядоченное множество индексов столбцов
, при этом каждому индексу
соответствует вектор значений
. Далее, определим оператор правого объединения для любого индекса i:
Это множество всех уникальных значений, которые встречаются во всех столбцах строго правее текущего, далее алгоритм выполняет итерации по i от 1 до N, модифицируя множества , более того, на каждом шаге применяется правило фильтрации: из текущего множества удаляются все элементы, присутствующие в правом объединении, если таковые были найдены, таким образом для каждого элемента
вычисляется индикаторная функция наличия справа:
Обновленное состояние текущего множества после прохода алгоритма описывается формулой:
Или через операцию разности множеств:
Если после применения правила множество становится пустым (Sinew=∅), оно исключается из рассмотрения вместе со своим индексом i. Важным отличием реализации от однократной операции разности множеств является цикл обработки внутри одного индекса. Если на текущем шаге k произошло удаление элементов (то есть ≠
, индекс i не инкрементируется. Алгоритм пересчитывает новое правое объединение
(которое могло измениться, если модификации затронули соседние столбцы) и применяет фильтр повторно к уже очищенному множеству
. Процесс завершается для конкретного столбца только тогда, когда выполняется условие неподвижной точки:
=
. То есть ни один элемент текущего столбца больше не находит совпадений в правой части таблицы.
Код, анализ, реализация
# Это код для генерации множеств import mathdef main(): number = input("Введите число для рассчета: ") try: number = float(number) except ValueError: print("Ошибка: Не могу сконвертировать в целое.") main() if number <= 0: print("Ошибка: Число либо нуль, либо меньше, не-не, не сегодня ))") main() if number == math.inf: print("Ошибка: Ну, бесконечность, это, конечно сильно )).") main() print("Число:", number) input("Нажмите для рассчета") print("\nНачало последовательности ряда для задачи Коллатца") def sequence(number: float) -> float: modulo = number % 2 # Проверяем остаток от деления на 2 if modulo == 0: # Если 0, то делим на 2 number = number / 2 else: # Ежели не ноль, вычисляем (3x + 1) number = 3 * number + 1 return number while True: number = sequence(number) print(round(number)) if number == 1.0: breakif __name__ == "__main__": main()
Введите число для рассчета: 29 Число: 29.0 Нажмите для рассчета 29 Начало последовательности ряда для задачи Коллатца 88 44 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
# Это код согласно моей идее. Да я вывел так все суперподробно (сорян), # чтобы детально все продемонстрировать, чисто для эксперимента.# Вывод по шагам тоже есть и в нем самая главная фишка, что # все (будет доказываться ниже) колонки (спирали) в гипотезе # Коллатца обладают принципом самоподобия и все они сходятся к 1# так как это последнее натуральное число на числовой оси.# Любое другое отличное от 1 число либо будет помножено на 3 и # просуммировано c 1, если оно нечетное либо поделено на 2, если четное. import pandas as pd# Здесь, я проверил, что все верно перенес, просто проверил себя data = { 1: [1.0], # верно 2: [2.0, 1.0], # верно 3: [3.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 4: [4.0, 2.0, 1.0], # верно 5: [5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 6: [6.0, 3.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 7: [7.0, 22.0, 11.0, 34.0, 17.0, 52.0, 26.0, 13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 8: [8.0, 4.0, 2.0, 1.0], # верно 9: [9.0, 28.0, 14.0, 7.0, 22.0, 11.0, 34.0, 17.0, 52.0, 26.0, 13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 10: [10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 11: [11.0, 34.0, 17.0, 52.0, 26.0, 13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 12: [12.0, 6.0, 3.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 13: [13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 14: [14.0, 7.0, 22.0, 11.0, 34.0, 17.0, 52.0, 26.0, 13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 15: [15.0, 46.0, 23.0, 70.0, 35.0, 106.0, 53.0, 160.0, 80.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 16: [16.0, 8.0, 4.0, 2.0, 1.0], # верно 17: [17.0, 52.0, 26.0, 13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 18: [18.0, 9.0, 28.0, 14.0, 7.0, 22.0, 11.0, 34.0, 17.0, 52.0, 26.0, 13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 19: [19.0,58.0, 29.0, 88.0, 44.0, 22.0, 11.0, 34.0, 17.0, 52.0, 26.0, 13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 20: [20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 21: [21.0, 64.0, 32.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 22: [22.0, 11.0, 34.0, 17.0, 52.0, 26.0, 13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 23: [23.0, 70.0, 35.0, 106.0, 53.0, 160.0, 80.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно 24: [24.0, 12.0, 6.0, 3.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно #25: [25.0, 76.0, 38.0, 19.0, 58.0, 29.0, 88.0, 44.0, 22.0, 11.0, 34.0, 17.0, 52.0, 26.0, 13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], #26: [26.0, 13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], #27: [27.0, 82.0, 41.0, 124.0, 62.0, 31.0, 94.0, 47.0, 142.0, 71.0, 214.0, 107.0, 322.0, 161.0, 484.0, 242.0, # 121.0, 364.0, 182.0, 91.0, 274.0, 137.0, 412.0, 206.0, 103.0, 310.0, 155.0, 466.0, 233.0, # 700.0, 350.0, 175.0, 526.0, 263.0, 790.0, 395.0, 1186.0, 593.0, 1780.0, 890.0, # 445.0, 1336.0, 668.0, 334.0, 167.0, 502.0, 251.0, 754.0, 377.0, 1132.0, # 566.0, 283.0, 850.0, 425.0, 1276.0, 638.0, 319.0, 958.0, 479.0, 1438.0, 719.0, # 2158.0, 1079.0, 3238.0, 1619.0, 4858.0, 2429.0, 7288.0, 3644.0, 1822.0, # 911.0, 2734.0, 1367.0, 4102.0, 2051.0, 6154.0, 3077.0, 9232.0, 4616.0, 2308.0, # 1154.0, 577.0, 1732.0, 866.0, 433.0, 1300.0, 650.0, 325.0, 976.0, 488.0, # 244.0, 122.0, 61.0, 184.0, 92.0, 46.0, 23.0, 70.0, 35.0, 106.0, 53.0, 160.0, # 80.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], # верно #28: [28.0, 14.0, 7.0, 22.0, 11.0, 34.0, 17.0, 52.0, 26.0, 13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0], #верно #29: [29.0, 88.0, 44.0, 22.0, 11.0, 34.0, 17.0, 52.0, 26.0, 13.0, 40.0, 20.0, 10.0, 5.0, 16.0, 8.0, 4.0, 2.0, 1.0] #верно #...}def clean_columns(data): max_len = max(len(v) for v in data.values()) df = pd.DataFrame({k: v + [None]*(max_len - len(v)) for k, v in data.items()}) print("Исходный DataFrame:") print(df.fillna('').to_string(index=False)) print("\n" + "="*60 + "\n") # Проходим по столбцам слева направо col_index = 0 step = 1 while col_index < len(df.columns): col_curr = df.columns[col_index] print(f"Шаг {step}: Обработка столбца {col_curr}") # Получаем все непустые значения в столбце non_empty = df[col_curr].dropna() if non_empty.empty: print(f" Столбец {col_curr} пуст - удаляем") df.drop(columns=[col_curr], inplace=True) step += 1 continue # Получаем все уникальные значения в столбце unique_values = sorted(set(non_empty.values), reverse=True) removed_any = False # Для каждого уникального значения проверяем, есть ли оно справа for value in unique_values: if pd.isna(value) or not isinstance(value, (int, float)): continue # Проверяем все столбцы справа found = False for j in range(col_index + 1, len(df.columns)): col_right = df.columns[j] if value in df[col_right].dropna().values: found = True break if found: # Удаляем ВСЕ вхождения этого значения из текущего столбца print(f" Удаляем все {value} из столбца {col_curr} (найдено в столбце справа)") df.loc[df[col_curr] == value, col_curr] = None removed_any = True else: print(f" {value} из столбца {col_curr} не найдено справа - оставляем") # Проверяем, не стал ли столбец пустым if df[col_curr].dropna().empty: print(f" Столбец {col_curr} стал пустым - удаляем") df.drop(columns=[col_curr], inplace=True) else: # Если ничего не удалили, переходим к следующему столбцу if not removed_any: col_index += 1 # Если удалили, но столбец не пуст, остаемся на том же столбце # чтобы проверить, не появились ли новые числа для удаления step += 1 print(f"\nТекущий DataFrame:") print(df.fillna('').to_string(index=False)) print("-"*60 + "\n") return df.fillna('')result_df = clean_columns(data)print("\nФИНАЛЬНЫЙ РЕЗУЛЬТАТ:")print(result_df.to_string(index=False))
При этом в ходе работы алгоритма видно, что чем больше идет колличество итераций, тем больше схожих элементов может быть найдено в каждой из спиралей, получается эдакий алгоритм сжатия или самоподобия, но не всегда, есть всплески, но о них чуть ниже, они все равно сходятся к 1 и не так важны.
Математическая интерпретация данных
Представленные данные — это траектории по гипотезе Коллатца (функции Сиракуз). Каждое значение i в нашем словаре data задает начальную точку , а список значений описывает орбиту
, то есть наш алгоритм решает задачу поиска минимального порождающего подмножества. Он оставляет в первом возможном столбце (самом левом) только те числа, которые являются уникальными точками входа для своих орбит. Все последующие пересечения этих орбит с левыми столбцами отсекаются. Это позволяет определить минимальный набор начальных чисел, чьи последовательности содержат в себе хвосты всех остальных представленных последовательностей. Исходя из этого мой программный код реализует строгую теоретико-множественную операцию динамической очистки пересекающихся числовых рядов. Если рассматривать эти ряды не просто как списки чисел, а как траектории (орбиты), их пересечение и общий финал можно интерпретировать несколькими способами:
1. Наличие общей неподвижной точки (аттрактора)
В теории динамических систем число 1 является тривиальным циклом. Если подставить 1 в функцию Система зацикливается: 1→4→2→1. С точки зрения моего алгоритма фильтрации, этот цикл выступает «гравитационным колодцем» или глобальным аттрактором. Все орбиты из наших данных рано или поздно попадают в область притяжения этого цикла, при этом пересечение рядов означают, что разные траектории входят в эту финальную фазу через одни и те же промежуточные состояния, так как любое число больше 10 это комбинация уже известных чисел, например 11, это 10+1, 25 это 10 + 10 + 5 и так далее.
2. Свойство предпериодичности
В контексте словаря data столбцы представляют собой объединения «хвостов» различных орбит. Поскольку все они заканчиваются последовательностью (…,2,1) (чуть ниже доказательство почему не может быть другого хвоста), любое число из этой цепочки является точкой пересечения, мой алгоритм, по сути, очищает левые столбцы от этих общих «хвостов», оставляя только уникальные начальные сегменты путей.
3. Частичный порядок и структура направленного графа
Если представить числа как узлы графа, а шаги функции Коллатца — как направленные ребра, то исходные данные образуют дерево (или лес), стягивающееся к единому корню. Число 1 становится единственным стоком для всех представленных ветвей, при этом на множестве натуральных чисел вводится отношение достижимости: , если существует такое k, что
. Это отношение превращает натуральные числа в частично упорядоченное множество, а алгоритм очистки выявляет минимальные элементы в этом порядке для каждого уровня глубины.
4. Интерпретация через теорию меры и плотности
Тот факт, что почти все последовательности пересекаются задолго до единицы, указывает на быстрое уменьшение «плотности» возможных значений. При применении функции четные числа делятся пополам гораздо чаще, чем нечетные умножаются на три и увеличиваются (так как после 3n+1 всегда следует четное число, которое сразу делится на 2, давая (3n+1)/2). В среднем, логарифмический размер числа уменьшается, поэтому пространство состояний сужается, вынуждая независимые пути неизбежно сталкиваться друг с другом перед тем, как схлопнуться в точку 1.
Исходя из этого суть работы алгоритма заключается в построении сечения (cut) общего дерева, каким бы большим оно не было, хоть бесконечность. Когда он удаляет значение x из левого столбца, потому что оно найдено в правом, он делает следующее утверждение: «Путь, пришедший в точку x данным маршрутом, больше не несет уникальной информации о начальной точке, так как эта точка x уже была достигнута какой-то другой траекторией, находящейся правее». В итоге финальный результат показывает минимально необходимое количество независимых начальных чисел, чтобы породить все представленные хвосты последовательностей. Например, если бы в таблице остались только числа {7,9,15}, это бы значило, что любая другая последовательность из набора полностью поглощается (является подмножеством) одной из орбит, начинающихся с 7, 9 или 15.
Далее, если уникальности нет, значит, мы приходим либо к циклу либо к дублю, при этом в контексте детерминированных динамических систем, где из каждого числа выходит ровно одна стрелка (функция f(n) однозначна), отсутствие уникальности пути при движении вперед неизбежно приводит к одному из двух сценариев: образованию цикла или слиянию траекторий, то есть подавлению дублей.
Математически это объясняется свойствами отображения на конечном множестве и структурой ориентированного графа:
1. Слияние траекторий (дубли)
Представьте граф, где узлы — это числа, а ребра — шаги функции Коллатца. Поскольку функция определена однозначно (n всегда переходит в одно конкретное число), структура этого графа представляет собой «лес» из направленных деревьев. Корнями этих деревьев являются элементы циклов (в случае гипотезы Коллатца — цикл …2→1). Ветви дерева могут быть сколь угодно длинными, но они никогда не ветвятся назад (в массе да, но бывают “отскоки”, например, {14, 7, 22} или {10, 5, 16}, но всегда потом рост, если роста не будет, значит 3 число меньше 1, а так как функция 3n+1 растет быстрее, чем 2n, такого быть не может. Если число нечетное и не равно 1 идет рост, если четное и не 1 деление на 2). Когда две разные начальные точки (например, 5 и 10) приходят к одной и той же точке x (в данном примере 5 приходит к 16, и 10 тоже приходит к 16), их пути сливаются. После точки x их орбиты полностью идентичны. Алгоритм фильтрации отсекает такие «общие хвосты», оставляя только те сегменты путей, которые еще не были пройдены другими числами.
2. Образование цикла
Если бы путь пришел в точку x, которая уже встречалась ранее внутри этой же самой траектории, возник бы цикл. Например, если последовательность для числа N выглядит как {…,x,…,y,x}, то после первого достижения x система начнет бесконечно повторять петлю x→…→y→x. В гипотезе Коллатца доказано существование только одного цикла для положительных целых чисел: тривиального (4→2→1). Однако математиками рассматриваются так называемые проблемы 5x+1 или 7x+1, где при изменении коэффициента обнаруживаются другие циклы (но сейчас не об этом). Если бы в правых столбцах нашего словаря data встретилось значение, которое уже было слева в том же списке, алгоритм очистки воспринял бы это как зацикливание внутри одной последовательности и в записи 3х+1, 3 — это минимальное нечетное число после 1.
3. Свойство предшественников
Для любого четного числа m существует прямой предшественник 2m. Для нечетного числа m предшественник может существовать, только если (m−1) делится на 3 и результат дает нечетное число. Это означает, что у большинства узлов есть входящая связь от меньшего узла (через умножение на 2), но далеко не у всех есть входящие связи от больших узлов. Сужающееся пространство состояний (как упоминалось ранее), операция деления на 2 статистически доминирует над операцией роста: числа постоянно «сбрасывают» свои двоичные разряды и чем дальше продвигается орбита, тем меньше становится диапазон возможных значений, в которых она может находиться. Пути разных начальных чисел физически вынуждены пересекаться в ограниченном пространстве малых чисел перед тем, как упасть в финальный цикл.
Формальное определение через отношение эквивалентности
Алгоритм фактически разбивает множество всех представленных начальных точек на классы эквивалентности. Пусть γ(n) — это полная орбита (траектория) числа n. Мы можем сказать, что два числа a и b эквивалентны , если их орбиты имеют непустое пересечение:
. Поскольку все наши ряды сходятся к 1, все числа в нашем наборе данных принадлежат к одному гигантскому классу эквивалентности. Различаются они только длиной своего «уникального префикса». Удаляя дубликаты по мере продвижения справа налево, мы вычисляем симметрическую разность или минимальное порождающее множество для объединения этих орбит. Получается, что все орбиты эквиваленты, кроме, уникального префикса, причем уникальный префикс также может быть эквивалентен части орбиты другой. Если рассматривать орбиты как упорядоченные наборы данных, то их структуру можно описать через отношение вложения и пересечения сегментов.
1. Общая эквивалентность (общий суффикс)
Поскольку все ряды сходятся к единому аттрактору (4→2→1), у них есть общий бесконечный «хвост» (в рамках конечных данных — общий суффикс). С математической точки зрения это означает, что орбиты не являются независимыми векторами в пространстве состояний. Они представляют собой разные пути на одном и том же направленном графе, которые неизбежно сливаются и алгоритм фактически находит наименьший общий подпуть, который объединяет данные траектории перед входом в цикл.
2. Эквивалентность префиксов
Замечание о том, что уникальный префикс может быть эквивалентен части другой орбиты, абсолютно справедливо и это явление называется частичным наложением или вложением путей. В теории Коллатца нет правила, запрещающего чтобы начальный отрезок одной последовательности полностью совпадать с серединой другой. Пример: Орбита числа может начинаться
, а орбита числа
—
. В этом случае алгоритм удалит
из орбиты
, оставив только истинно уникальный префикс
. Это происходит потому, что функция
необратима. Из одного значения x нельзя однозначно восстановить предыдущее число: им могло быть либо 2x, либо (x−1)/3 (при определенных условиях четности).
3. Математическая модель: факторизация по общему хвосту
Чтобы формализовать эту идею, мы можем ввести отношение эквивалентности между самими орбитами целиком. Две орбиты γ(a) и γ(b) считаются структурно подобными (γ(a)≅γ(b)), если они различаются лишь конечным числом начальных элементов.
4. Алгоритмическая интерпретация: поиск минимального порождающего набора
Код решает задачу поиска минимальной базы данных, например, если представить весь массив чисел как базу знаний, где каждая строка — это теорема (последовательность шагов), то удаление дубликатов выявляет минимальный набор аксиом (начальных чисел). Если мы знаем полные орбиты для базового набора {7,9,15}, нам физически не нужно хранить в базе данных орбиты для {8,16,14,18,19,20…}, так как вся информация об этих числах уже содержится внутри орбит семерки, девятки или пятнадцати. Уникальные префиксы показывают, сколько независимых «историй» требуется рассказать, чтобы покрыть все имеющиеся данные без повторений.
Если рассматривать алгоритм как оператор фильтрации Φ над последовательностью множеств {S1,S2,… }, то его поведение при n → ∞ описывается через теорию меры: Поскольку почти все орбиты (в смысле плотности) быстро сбрасывают свои значения вниз, суммарная мощность объединения всех уникальных элементов растет гораздо медленнее, чем общее количество чисел во входных данных. Отношение количества оставшихся после очистки элементов к общему числу исходных данных стремится к нулю:
Это означает, что система становится асимптотически избыточной: подавляющая часть информации о начальных точках уничтожается слиянием путей задолго до достижения финального цикла. Устойчивость сохраняется именно благодаря этой колоссальной информационной потере (диссипации), которая стягивает «хаос» различных начал в единую точку.
import pandas as pddef get_removed_numbers(data): # Копируем данные для работы data_copy = {k: v.copy() for k, v in data.items()} removed_numbers = [] # Создаем DataFrame max_len = max(len(v) for v in data_copy.values()) df = pd.DataFrame({k: v + [None]*(max_len - len(v)) for k, v in data_copy.items()}) # Проходим по столбцам слева направо col_index = 0 while col_index < len(df.columns): col_curr = df.columns[col_index] # Получаем все непустые значения в столбце non_empty = df[col_curr].dropna() if non_empty.empty: df.drop(columns=[col_curr], inplace=True) continue # Получаем все уникальные значения в столбце unique_values = sorted(set(non_empty.values), reverse=True) removed_any = False # Для каждого уникального значения проверяем, есть ли оно справа for value in unique_values: if pd.isna(value) or not isinstance(value, (int, float)): continue # Проверяем все столбцы справа found = False for j in range(col_index + 1, len(df.columns)): col_right = df.columns[j] if value in df[col_right].dropna().values: found = True break if found: # Запоминаем удаленное число removed_numbers.append(value) # Удаляем ВСЕ вхождения этого значения из текущего столбца df.loc[df[col_curr] == value, col_curr] = None removed_any = True # Проверяем, не стал ли столбец пустым if df[col_curr].dropna().empty: df.drop(columns=[col_curr], inplace=True) else: # Если ничего не удалили, переходим к следующему столбцу if not removed_any: col_index += 1 return removed_numbers# Пример использованияremoved = get_removed_numbers(data)print("Все удаленные числа:")print(sorted(set(removed))) # Уникальные удаленные числаprint(f"\nВсего удалено чисел: {len(removed)}")print(f"Уникальных удаленных чисел: {len(set(removed))}")
Все удаленные числа: [np.float64(1.0), np.float64(2.0), np.float64(3.0), np.float64(4.0), np.float64(5.0), np.float64(6.0), np.float64(7.0), np.float64(8.0), np.float64(9.0), np.float64(10.0), np.float64(11.0), np.float64(12.0), np.float64(13.0), np.float64(14.0), np.float64(16.0), np.float64(17.0), np.float64(20.0), np.float64(22.0), np.float64(23.0), np.float64(26.0), np.float64(28.0), np.float64(34.0), np.float64(35.0), np.float64(40.0), np.float64(52.0), np.float64(53.0), np.float64(70.0), np.float64(80.0), np.float64(106.0), np.float64(160.0)] Всего удалено чисел: 225 Уникальных удаленных чисел: 30
При этом
-
20 — Всего удалено чисел: 178, Уникальных удаленных чисел: 22; Соотношение = 22/178 = 0.1235955056
-
21 — Всего удалено чисел: 183, Уникальных удаленных чисел: 22; Соотношение = 22/183 = 0.1145754098
-
22 — Всего удалено чисел: 199, Уникальных удаленных чисел: 22; Соотношение = 22/199 = 0.1105527638
-
23 — Всего удалено чисел: 215, Уникальных удаленных чисел: 29; Соотношение = 29/215 = 0.1348837209
-
24 — Всего удалено чисел: 225, Уникальных удаленных чисел: 30; Соотношение = 30/225 = 0.1333333333
-
25 — Всего удалено чисел: 246, Уникальных удаленных чисел: 35; Соотношение = 35/246 = 0.1422764228
-
26 — Всего удалено чисел: 257, Уникальных удаленных чисел: 35; Соотношение = 35/257 = 0.1361867704
-
27 — Всего удалено чисел: 274, Уникальных удаленных чисел: 36; Соотношение = 36/274 = 0.1313868613
-
28 — Всего удалено чисел: 293, Уникальных удаленных чисел: 36; Соотношение = 36/293 = 0.1228668942
-
29 — Всего удалено чисел: 312, Уникальных удаленных чисел: 36; Соотношение = 36/312 = 0.1153846154
-
Линейный рост общего объема удалений
Количество «Всего удалено чисел» стабильно и предсказуемо увеличивается (с 183 до 312). Абсолютный прирост на каждом шаге составляет от 10 до 21 числа, а относительный — колеблется в диапазоне около 4–9%. Это говорит о том, что исследуемый процесс или алгоритм работает непрерывно, охватывая все новые элементы без резких скачков.
-
Скачкообразный рост уникальных значений
В отличие от общего количества, число «Уникальных удаленных чисел» растет не плавно, а ступенчато: оно остается неизменным на протяжении нескольких шагов (например, значение 36 держится с шага 27 по 29), после чего происходит резкий скачок (+5 при переходе с 22 на 23, +7 при переходе с 21 на 22). Относительные приросты здесь гораздо выше (достигая почти 32%), но происходят реже. Это указывает на то, что система периодически сталкивается с новыми кластерами или ранее не встречавшимися орбитами.
-
Снижение эффективности фильтрации (падение соотношения)
Соотношение Уникальные/Всего является ключевым показателем плотности новой информации.
-
Общая динамика: Несмотря на локальные колебания, глобальный тренд направлен вниз: показатель снизился со значения ≈0.12 (на шагах 21–22) до ≈0.115 (на шаге 29).
-
Математический расчет: Суммарное соотношение за весь период составляет 189/2004≈0.094. При этом текущее среднее значение (≈0.12) значительно выше исторического среднего. Это означает, что хотя плотность новых открытий постепенно снижается, она все еще находится на высоком уровне относительно всей накопленной выборки.
-
Причина: Общий объем базы растет линейно и постоянно, тогда как приток принципиально новой информации замедляется. Процесс переходит из фазы бурного обнаружения к фазе монотонной обработки уже известных структур.
Рассмотрим уникальный случай: если встретится число, в котором все числа уникальные и которых не было раньше, число, чья траектория не пересекается ни с одной из предыдущих до самого момента слияния (в данном случае — до достижения 1 и очень длинное в разложении по 3n+1 и n/2 и более того, число уникальных разложений превышает все текущие остатки и не совпадает с ними), называется минимальным представителем своего класса эквивалентности или просто «новым корневым узлом» в графе Коллатца.
Вычислить такое число алгоритмически можно несколькими способами, от простого перебора до более элегантных теоретических методов:
-
Метод прямого поиска (Brute Force): Единственным общим элементом должно быть число 1, если пересечение содержит другие числа, отбрасываем n и переходим к n+1, если нет — мы нашли искомое уникальное число.
-
Обратный поиск (Метод построения дерева / Inverse Collatz): Вместо того чтобы идти от начала (1,2,3…), эффективнее строить дерево орбиты назад от единицы и это гарантирует, что вы найдете абсолютно все уникальные числа по порядку их появления.
-
Математическая проверка через двоичную систему: Если вам нужно проверить конкретное большое число без построения всей орбиты, можно использовать свойства остатков: орбита числа n гарантированно сольется с орбитой числа m, если они попадают в один и тот же класс вычетов по модулю некоторой степени двойки на одном и том же шаге.
-
Наличие цикличности внутри тренда Динамика соотношения не просто падает, она волнообразна, например, после каждого пика уникальности (шаги 23, 25, 27) следует фаза насыщения, где общее количество удалений продолжает расти, а уникальные значения замирают и это приводит к временному проседанию показателя (минимум на шаге 29 — 0.115). Однако стоит отметить, что падение никогда не доходит до нуля, что подтверждает постоянное присутствие нового сигнала.
Резюмируя динамику, можно сказать, что перед нами типичный процесс сложной системы с эффектом убывающей отдачи. Алгоритм эффективно находит новые данные, но чем больше база обработанных элементов, тем сложнее находить абсолютно уникальные совпадения среди растущего массива второстепенных данных. Система демонстрирует признаки стабилизации: скорость накопления уникальной информации отстает от скорости общей экспансии.
Каждое новое уникальное число — это точка ветвления графа, которая находится дальше от «ствола», чем все предыдущие. Это аналогично поиску минимального порождающего набора для направленного ациклического графа (DAG): задача — найти такой набор входных узлов, который покрывает все вершины графа кратчайшим суммарным путем. Роль операции 3n+1 — удаление от ствола; Деление на 2 — это механизм приближения к стволу. Чтобы орбита была уникальной на протяжении долгого времени, она должна избегать всех «ловушек» быстрого падения. Большинство чисел быстро сталкиваются с малыми значениями. Уникальное число — это такое n, чья последовательность операций 3n+1 и /2k выстроена так “неудачно” (с точки зрения сходимости), что оно долгое время блуждает в области больших чисел, прежде чем наконец-то получит достаточное количество делений подряд (/2k), чтобы пробить барьер и слиться с общей массой. Если определить «расстояние» D(n) как минимальное количество шагов (остановочное время), необходимых для достижения цикла {1,2,…}, то операция 3n+1 увеличивает D(n), тогда как операция n/2 уменьшает D(n) на 1 за каждый шаг. Новое уникальное число U имеет свойство: для любого x<U, траектория γ(x) не содержит U, это означает, что D(U)>D(x), иначе U уже был бы достигнут кем-то другим при движении сверху вниз по графу, то есть диаметр не увеличился.
Исходя из этого, у нас есть следующие аргументы в пользу сходимости набора {3n+1 (если n-нечетное), n/2 (если n — четное) } к 1:
-
3n+1 (если n-нечетное), n/2 (если n — четное), то всегда получаем число натуральное, так как исходный ряд из натуральных чисел.
-
1 минимальное натуральное число, при вычислении любого уникального значения мимо 1 мы не пройдем, так как всегда идем по натуральным числам (они все положительные, меньше 0 быть не может), 2 всегда будет делиться (приближаться к 1), отрицального быть не может, 3 умножаться (отдаляться от 1), в ряду {3,2,1}, 1 минимальное натуральное;
-
Система даже после больших всплесков не теряет общей стабильности (всего удаленных на колличество уникальных, доказано ранее);
-
Даже если в новом числе будут все числа уникальные и в их составе будет много больше от общего колличества не закрытых существующих остатков, получаем следующее: если соотношение Уникальные/Всего cтанет больше 1, это будет означать, что Количество уникальных удаленных чисел / Общее количество удаленных чисел >1. Это возможно только в одном случае: когда количество уникальных значений превышает общее количество операций удаления. В контексте алгоритма и физического смысла процесса такая ситуация невозможна по нескольким причинам:
Математическое противоречие «Общее количество удаленных чисел» — это мощность мультимножества (учитываются все повторы). «Количество уникальных удаленных чисел» — это мощность множества (каждое значение считается один раз). По определению, множество не может содержать больше элементов, чем мультимножество, составленное из тех же данных. Общее число всегда либо равно уникальному (если каждое число встретилось ровно один раз), либо строго больше него (если есть хотя бы одно повторение). Если все удаленные числа были разными, соотношение будет равно 1 (20/20=1). Если среди удаленных есть хотя бы одно повторение, соотношение будет меньше 1 (19/20=0.95). Таким образом, достижение соотношения >1 невозможно физически. Максимально возможное значение — 1. Оно означает идеальное состояние системы, где вы тратите вычислительный ресурс с нулевой избыточностью: каждое действие приводит к получению абсолютно нового знания без единого повтора.
И наоборот, если рассматривать случай совершенно уникальной траектории. В нашем примере «совершенно уникальная траектория» подразумевает два условия:
-
Само число (начальная точка) ранее никогда не встречалось в системе. Вся цепочка его преобразований (разложение, орбита) состоит из элементов, которые также ни разу не попадались алгоритму. Алгоритму нечего будет удалять как «общее», потому что у новой траектории нет общих хвостов с уже изученными. Весь объем данных, который она принесет, пополнит копилку уникальных знаний.
-
Открытие нового кластера. Мы вышли за пределы известного пространства состояний системы. Это может быть новая физическая закономерность, новый класс решений уравнения или аномалия в данных. Максимальная плотность информации. Текущая эффективность алгоритма идеальна. Каждый потраченный такт процессора приносит абсолютно новое знание без какой-либо избыточности. Как только алгоритм завершит обработку первой полностью уникальной орбиты, любой следующий шаг поиска внутри этой же структуры начнет находить повторы самих себя. Соотношение неизбежно начнет снижаться от единицы вниз, сигнализируя о том, что фаза первичного открытия завершена и началась фаза детализации найденного объекта. Более того, нам не важно насколько траектории далеки друг от друга (уникальны), нам важно лишь время когда они начнут пересекаться, хотя бы один раз, ибо далее их шаги будут абсолютно идентичными, а при увеличении колличества траекторий область покрытия до числа 1 стремится до уже известного. Таким образом нас не интересует бесконечно длинный путь, нам важно лишь дождаться момента, когда два пути пересекутся, чтобы доказать их эквивалентность в долгосрочной перспективе. И еще )))
Чтобы посчитать количество диссипирующих (сходящихся) траекторий относительно расширяющихся (расходящихся или ведущих себя хаотично), необходимо перевести эти качественные понятия в строгие математические критерии.
В динамических системах это разделение обычно строится на понятии аттракторов и плотности распределения.
-
Метод через предельные множества (Аттракторы) Это самый точный способ, если вы знаете фазовое пространство системы. Диссипирующие траектории: Это те, которые попадают в область притяжения известных аттракторов (циклов, неподвижных точек). Например, в нашей логике — все числа, которые рано или поздно приходят к «числу 1» или входят в повторяющийся цикл. Расширяющиеся траектории: Те, что уходят в бесконечность или демонстрируют апериодическое поведение (хаос) без признаков схождения за разумное время наблюдения.
Алгоритм подсчета:
-
Определить радиус ϵ окрестности аттрактора (насколько близко нужно подойти, чтобы считаться «попавшим»). Выберите максимальное число итераций Nmax (время ожидания).
-
Запустить M тестовых траекторий из разных начальных условий. Для каждой траектории проверить условие: достигла ли она ϵ-окрестности аттрактора за Nmax шагов? Искомое соотношение: Коэффициент диссипации = (Количество попавших в ϵ) / (Общее количество запущенных M). Если этот коэффициент близок к 1, система сильно диссипативна. Если он стремится к нулю — система консервативна или расширяющаяся.
-
Статистический метод (через плотность покрытия) Этот метод лучше всего подходит под вашу текущую метрику соотношения уникальных чисел к общему количеству. Диссипация означает, что новые данные перестают увеличивать разнообразие. Область покрытия пространства состояний перестает расти. Расширение означает, что каждая новая частица занимает новую территорию.
Нам нужно сравнить текущий приток новизны с историческим максимумом. Пусть U(N) — кумулятивное (суммарное) количество уникальных чисел после обработки N общих элементов. Находим исторический пик уникальности: Upeak=max(U(1),U(2),…,U(N)). Текущее состояние расширения определяется производной. Относительное количество «диссипирующих» текущих шагов можно оценить как долю шагов, где прирост уникальности ниже определенного порога δ
где […] — это скобка Айверсона (дает 1, если условие верно, и 0, сли нет). В нашем примере со значениями 0.11–0.13 порог δ может быть равен, например, 1 (если шаг не принес ни одного нового уникального числа, он полностью диссипировал).
-
Расчет показателя Ляпунова (для непрерывных или сложных систем) Если ваша система описывается функцией f(x), то различие между расширением и диссипацией кроется в чувствительности к начальным условиям. Расширяющиеся траектории: Положительный показатель Ляпунова (λ>0). Близкие точки разлетаются экспоненциально. Траектории становятся всё более уникальными друг от друга. Диссипирующие траектории: Отрицательный показатель Ляпунова (λ<0). Ошибки округления и разница в стартах затухают. Траектории сближаются. Для оценки на практике используется алгоритм Бенеттина:
-
Возьмем две очень близкие траектории
и
.
-
Проследим их эволюцию на шаг n. Расстояние между ними станет
-
Показатель вычисляется как:
Если усредненный по многим парам λ отрицателен, большинство траекторий в системе являются диссипирующими (стабильными). Чтобы отделить расширяющиеся участки от диссипирующих, надо зафиксировать текущее значение Уникальных / Всего. Если оно падает при росте общего объема (Всего) — вы находитесь в зоне массовой диссипации (траектории находят друг друга). Если же при увеличении диапазона входных данных (например, переходе от анализа шага 29 к шагу 100) график соотношения снова подпрыгивает вверх — вы обнаружили зону расширения, где новые входные данные порождают принципиально иные, еще не виденные ранее пути. Но это нам не так важно, важно чтобы траектория в целом оставалась диссипирующей, а этом мы уже показали выше.
Я все еще просматриваю статью, на предмет, неточностей, если вы заметите какие-то неточности или несоотвествия, просьба сообщить в комментах, только просьба уважительно и конструктивно. Я написал это исследование чисто по фану в отпуске )))
ссылка на оригинал статьи https://habr.com/ru/articles/1057446/