2014 dxdy logo

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

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




На страницу Пред.  1, 2
 
 Re: Равенство корней двух многочленов
Сообщение29.01.2026, 22:21 
Именно так. Вы же порядок на переменных задаёте как угодно, нужную переменную всегда можно сделать последней.

 
 
 
 Re: Равенство корней двух многочленов
Сообщение01.02.2026, 22:44 
Аватара пользователя
Который день пытаюсь запрограммировать этот алгоритм Бухбергера. В книжке это дело очень просто звучало, особенно когда они там в примерах несколько последовательных (по их определению) операций редуцирования сокращали до одной стрелочки (и даже не заикнулись об этом, ну да ладно).

Два дня потратил на то, чтобы запрограммировать парсер человеческих формул, не смотря на то, что он примитивный, как в дешёвом калькуляторе: без стека, без скобок, без возведения чисел в степень (только переменные). Единственное, что хорошо, — он порядок действий сложение/вычитание и умножение делает правильно (и возведение переменных в степень). В результате получилось два прохода: разбивка текста на токены и сбор информации о задействованных переменных в первом проходе, а после формирования структуры данных "множество переменных" (со своим упорядочиванием на нём) делается второй проход, который найденные токены собирает уже в мономы и полиномы.

Тут ещё оказалось важным определиться с тем, как представлять в памяти данные о полиномах. Я пришёл к выводу, что очень логично определить объект "множество переменных", хранящих их имена и упорядоченность. Внутри этого объекта находятся зависимые объекты: мономы и полиномы. Они обращаются к множеству для конвертирования имён переменных в индексы при создании новых мономов и полиномов по строкам (для чего есть третий билдер-объект), а также для вывода результатов в виде текста. Получилось, что вся критическая информация инкапсулирована, и вне объекта ничего нельзя напутать, даже если попытаться сделать это нарочно.

Сегодня весь день потратил на реализацию собственно операций над мономами и полиномами, включая редукцию и зацепление, как в книжке. Теперь есть все "кирпичики", из которых можно построить алгоритм Бухбергера. Правда я их реализовал по принципу "quick and dirty", чтобы быстрее получить результат. Основной упор был сделан на реализацию в таком виде, чтобы по максимуму исключить возможные ошибки, а не чтобы работало быстро. Я усиленно проделанное ещё не тестировал, но элементарные вещи оно делает правильно.

В книжке алгоритм Бухбергера предлагается реализовывать приблизительно так:
  1. Ищем все возможные зацепления между полиномами в списке и строим соответствующие производные многочлены, кладём их в очередь.
  2. Полученные результаты достаём из очереди один за другим и редуцируем с помощью имеющихся в списке полиномов. Если результат нетривиальный (отличен от нуля), то кладём его в список полиномов, пополняя соответствующим образом очередь производных полиномов (зацепления нового полинома с уже имеющимися).
  3. Повторяем второй пункт до победного. Победа наступает, когда очередь опустеет, то есть все зацепления старых и новых полиномов будут разрешимы (редуцируемы в нуль). Ну, или когда редукция приведёт к "полиному"-константе, что будет означать, что система несовместна.

Мне тут сразу видится неоптимальность: исходный список может содержать полиномы, которые редуцируются уже имеющимися в списке (а не новыми создаваемыми). Если эта редукция в нуль, то, на мой взгляд, такой полином можно сразу исключить из списка, даже если список ещё не является базисом Грёбнера. Я же прав в этом моменте?

 
 
 
 Re: Равенство корней двух многочленов
Сообщение02.02.2026, 04:34 
Алгоритм из книжки далеко не самый оптимальный, зато простой. И получение константы — это не исключительный случай, просто об неё всё остальное редуцируется.

 
 
 
 Re: Равенство корней двух многочленов
Сообщение02.02.2026, 10:36 
Аватара пользователя
dgwuqtj, так всё-таки верно ли утверждение? Если многочлен редуцируется другими в ноль, то его из списка можно удалить, даже если список ещё не является базисом Грёбнера?

-- 02.02.2026, 10:53 --

B@R5uk в сообщении #1716959 писал(а):
Если многочлен редуцируется другими в ноль, то его из списка можно удалить...
Если многочлен редуцируется набором других многочленов в ноль, то его можно представить как линейную комбинацию этих многочленов (с коэффициентами из кольца многочленов), то есть это означает, что редуцируемый многочлен принадлежит идеалу, построенному только на редуцирующих многочленах, поэтому его добавление и/или удаление из списка не изменит этот идеал. И поэтому его можно удалить.

Это же правильное доказательство корректности операции?

 
 
 
 Re: Равенство корней двух многочленов
Сообщение02.02.2026, 10:56 
B@R5uk в сообщении #1716959 писал(а):
Если многочлен редуцируется другими в ноль, то его из списка можно удалить, даже если список ещё не является базисом Грёбнера?

Верно, идеал же не изменится. Но не факт, что вы от этого выиграете, придётся делать кучу дополнительных проверок.

 
 
 
 Re: Равенство корней двух многочленов
Сообщение02.02.2026, 11:09 
Аватара пользователя
dgwuqtj в сообщении #1716961 писал(а):
придётся делать кучу дополнительных проверок.
Наоборот. Эти проверки явно или неявно всё равно делаются, когда строятся зацепления многочленов. Если новый многочлен редуцирует какие-то уже имеющиеся в ноль, то эти имеющиеся можно удалить, потому что зацепления с ними будут только засорять очередь. А начать алгоритм надо с пустого списка, запихнув все стартовые многочлены в очередь. Внутри итерации будет доставаться один-единственный многочлен из очереди и над ним (с многочленами из списка) будут проделываться все необходимые корректные операции.

В конце-концов, в книжке явно говорится, что порядок операций не важен (лишь бы все зацепления были проверены для конечного списка), минимальный базис единственен. Если я по пути (а не в самом конце) выкину очевидные зависимые многочлены, то процесс от этого только выиграет, так как потребуется строить значительно меньше зацеплений.

Я что-то похожее делал, когда решал задачу построения группы по её заданию соотношениями между образующими. Там, правда, не было теоретической гарантии, что процесс остановится, как это есть с многочленами.

-- 02.02.2026, 11:36 --

Тут ещё надо, наверно, очередь сделать с приоритетом. Потому что нет смысла редуцировать многочлены с младшими переменными и добавлять результат в список, когда в очереди ещё остались многочлены со старшей переменной. Какой именно многочлен лучше выбирать из имеющихся в очереди с заданной старшей переменной — мне пока не понятно. С одной стороны, меньшая суммарная степень самого старшего монома позволит чаще делать редукцию других многочленов, (предположительно) уменьшая общее число операций (хотя, возможно, увеличивая сложность каждой итерации). С другой стороны, меньшая степень старшей переменной кажется лучшим выбором. Пока нет чёткой определённости, что лучше, сделаю обычную очередь: первый пришёл — первый вышел.

 
 
 
 Re: Равенство корней двух многочленов
Сообщение02.02.2026, 13:45 
Аватара пользователя
B@R5uk в сообщении #1716962 писал(а):
...меньшая суммарная степень самого старшего монома позволит чаще делать редукцию других многочленов, (предположительно) уменьшая общее число операций...
Не, так себе подход. Контрпример. Если редуцировать начинать с помощью полиномов p младшей степени, то полином q, который, возможно, редуцировался бы полиномом самой старшей степени P (из имеющихся в списке) уже может оказаться не редуцируемым с его помощью. Тогда (в предположении, что остаток от q после редукции не нулевой) информацию, заключённую в паре полиномов q и P, можно будет извлечь только построив их зацепление, что более трудоёмко, чем просто редукция оригинального q с помощью P (особенно учитывая, что редукция, как правило, значительно увеличивает в полиноме количество мономов с младшими переменными).

С другой стороны, если начать с младших полиномов p, то полином q может оказаться редуцируемым в ноль, но не после того, как он был сначала редуцируем с помощью полинома P. Вот если бы для полиномов списка можно было доказать, что последняя ситуация невозможна, то всё бы однозначно встало на свои места, и редуцировать надо было бы начинать с полиномов старшей степени.

Пока мне видится такая реализация алгоритма Бухбергера:
  1. Инициализация. Завести упорядоченный список полиномов и простую очередь. Список оставить пустым, очередь заполнить исходными полиномами.
  2. Главный цикл. Повторять, пока очередь не пуста.
    1. Достать полином из очереди.
    2. Редуцировать его с помощью всех полиномов из списка начиная со старшего (цикл по списку).
    3. Если результат нулевой, перейти к следующей итерации.
    4. Если результат константа, то закончить работу алгоритма, выдав в качестве базиса Грёбнера один-единственный полином-константу "1".
    5. Остаток редуцирования — нетривиальный полином R. Проверить редуцируемость полиномов списка с его помощью (цикл по списку). Редуцируемые в ноль полиномы списка удалить, а нетривиально редуцируемые — удалить и добавить остаток в очередь (потому что эти остатки могут редуцировать другие полиномы списка или сами редуцироваться с их помощью — это всё будет проверено на следующих итерациях).
    6. Построить все зацепления полинома R с полиномами списка и добавить результаты в очередь (цикл по списку).
    7. Добавить полином R в список в соответствии с порядком.
  3. Выдать в качестве минимального базиса Грёбнера список полиномов.
В качестве списка полиномов лучше всего использовать упорядоченное множество. Оно гарантирует логарифмическое (от размера множества) время добавления очередного элемента (в отличие от линейного для связного списка или массива), а так же гарантирует порядок при итерировании по нему.

(РАЗМЫШЛЕНИЯ О ТРУДОЁМКОСТИ)

По идее, порядок и содержимое пунктов 5 и 6 должно гарантировать, что число операций зацепления, выполняемых в процессе алгоритма минимально. Нет смысла стоить зацепление, когда один полином редуцирует другой. Вернее, в результате такого зацепления получится результат редукции. Но при этом пункт 5 гарантирует, что добавляемый в список в пункте 7 полином R не редуцирует никакой полином списка. Это гарантирует минимальность списка на любой итерации, что в свою очередь должно гарантировать минимальность зацеплений. "Должно" — потому что число итераций может оказаться при таком подходе гораздо больше. То есть я уменьшаю один из множителей произведения (в формуле трудоёмкости, делаю это, потому что гарантированно могу), но это может происходить за счёт несоразмерного увеличения второго множителя, что, вопреки желанию, может привести к росту этого самого произведения.

Алгоритм корректен, потому что он:
  1. Не теряет информацию. Полиномы отбрасываются, только когда они редуцируемы в ноль, то есть представимы в виде линейной комбинации полиномов некоторого подмножества всего множества полиномов (список плюс очередь).
  2. Все зацепления в списке редуцируемы (пункт 6 алгоритма обеспечивает это).
  3. Полиномы списка не редуцируют друг друга (пункт 5, минимальность списка).

Я же нигде ничего не напутал?

 
 
 
 Re: Равенство корней двух многочленов
Сообщение02.02.2026, 14:56 
Можно редуцировать сначала по многочленам с наименьшим старшим членом, чтобы остаток сразу был маленьким. Пункт II.4 не нужен, об константу всё остальное сразу редуцируется в 0 и получится базис из одной константы.

 
 
 
 Re: Равенство корней двух многочленов
Сообщение02.02.2026, 17:32 
Аватара пользователя
Сделал я эту программу и даже обкатал её на примерах из пункта 4.7 книжки, сравнив результаты с ответом. В целом всё правильно, но моя программа иногда выдаёт отличающиеся формулы. Отличия в первую очередь в том, что в книжке авторы при решении задач редуцируют не только старший член полинома, но и младшие. Формально, они нигде не писали, что так надо делать. В параграфе 3 на странице 30 даётся определение, что такое редукция, и в нём речь идёт только о самых старших членах полинома. В задачах же один пример даже подобран так, что за счёт этой расширенной редукции один из полиномов в ответе получается значительно короче (пара членов сократилась). Но в общем случае, я думаю, это расширенное редуцирование может приводить к неконтролируемому росту длины полиномов, потому что каждое редуцирование добавляет к редуцируемому полиному число слагаемых, на единицу меньшее, числа членов редуцирующего полинома — потому что не факт что все эти новые члены объединятся с уже имеющимися, а тем более сократятся. Поэтому я эту функцию реализовывать не буду. Кроме того, формально у меня правильно, и меня интересует лишь самый последний полином в базисе — от одной переменной, на него это влиять не должно.

В примерах есть вот такие две задачи (выписываю их с ответами), которые, видимо, призваны продемонстрировать что-то, но я в упор не понимаю что: $$\Bigl\{x^2-1,\;(x-1)y,\;(x+1)z\Bigr\}\to\Bigl\{x^2-1,\;(x-1)y,\;(x+1)z,\;yz\Bigr\}$$ $$\Bigl\{x^2-1,\;(x-1)y,\;(x-1)z\Bigr\}\to\Bigl\{x^2-1,\;(x-1)y,\;(x-1)z\Bigr\}$$ Не понимаю, как этот дополнительный моном в списке появился в первом случае.

Теперь надо написать код, который перед моим решателем-поисковиком базисов идеалов поставит реальную задачу, простейшую из тех, что мне потребуется решать. Что-то меня берут сомнения, что моя реализация алгоритма осилит (по быстродействию и расходу памяти) их решение...

 
 
 
 Re: Равенство корней двух многочленов
Сообщение02.02.2026, 17:47 
B@R5uk в сообщении #1716999 писал(а):
Не понимаю, как этот дополнительный моном в списке появился в первом случае.

$((x + 1) z) y - ((x - 1) y) z = 2 y z$, так что всё правильно.

 
 
 
 Re: Равенство корней двух многочленов
Сообщение02.02.2026, 18:28 
Аватара пользователя
Да, понял. Косяк где-то в моей программке, она зацепления в этих примерах вообще не находит (хотя в других случаях всё хорошо). Надо разобраться в чём дело.

-- 02.02.2026, 18:59 --

Изображение Дело было в условии. Скопипастил из книжки формулы в текст кода, кавычки поставил, минусы исправил, символ возведения в степень добавил, а пробелы между переменными добавить забыл. В результате программа прочитала эти xy и xz как отдельные новые переменные (с длинным именем). Почти до самого дна стека подпрограмм докопался, только после этого увидел, что у меня массивы степеней переменных у мономов что-то слишком длинные (потому что переменных слишком много), хотя программа список этих переменных первой же строчкой печатает как раз на этот случай. Эх!..

 
 
 
 Re: Равенство корней двух многочленов
Сообщение03.02.2026, 10:10 
Аватара пользователя
И конечно же, алгоритм выше на реальных данных загибается. Даже такая вот примитивная система из пяти уравнений (без последнего в списке, с ним — осиливает) на координаты тетраэдра не решается за разумное время (и требует в процессе абсолютно безрассудное количество памяти): $$\begin{array}{r}a^2+d^2-1=0\\b^2+c^2+d^2-1=0\\a^2+(d-1)^2-z^2=0\\b^2+c^2+(d-1)^2-z^2=0\\(a-b)^2+c^2-z^2=0\\b^2+4c^2+d^2-z^2=0\end{array}\qquad\qquad\begin{array}{llrr}1:&(\;0,&0,&1\;)\\2:&(\;a,&0,&d\;)\\3:&(\;b,&c,&d\;)\\4:&(\;b,&-c,&\phantom{-}d\;)\end{array}\qquad\qquad\begin{tikzpicture}\draw[dotted](-1.2,0.5)--(0.6,0.8)\draw(0.3,0)--(0,2)--(-1.2,0.5)--(0.3,0)--(0.6,0.8)--(0,2)\node at(0.3,2){1}\node at(0.3,-0.3){2}\node at(-1.2,0.2){3}\node at(0.8,0.8){4}\end{tikzpicture}$$

В процессе получаются гигантские полиномы с безумными коэффициентами (текстовый файл с записью только одного весит до 13 кБ и больше). На сколько я понял из вывода промежуточных результатов моя стратегия получить минимальный базис как можно скорей привела к совершенно противоположным от желаемых результатам: при редуцировании длина полиномов растёт экспоненциально быстро. А всё потому, что при редуцировании длинными полиномами они удлиняют редуцируемые. Вывод из этого следующий. Надо в первую очередь редуцировать с помощью коротких полиномов (длины 1 член, если имеется, затем длины 2 члена, если имеется, и так далее). После длины надо смотреть на степень полинома: чем больше, тем лучше. И только после этого на старшинство старшего монома в лексикографическом порядке. Очевидно, чтобы список редуцирующих полиномов имел достаточное их количество с короткой длиной, нельзя из него выбрасывать исходные и вновь получаемые полиномы, даже если они оказываются сами редуцируемы с помощью других полиномов списка. Потому что результат почти всегда будет длиннее. Разумеется, из очереди тоже надо доставать по возможности более короткие полиномы с большей суммарной степенью при старшем мономе.

Следующая стратегическая ошибка, которую я допустил, — это вычисление зацеплений по принципу "как только, так сразу" с последующим бездумным засовыванием результата в очередь. Как следствие, к моменту, когда до этого результата дойдёт очередь (pun intended), один или оба его "прародителя", как правило, окажутся сами редуцированными и этот результат можно откидывать, а не тратить на него дополнительное время. Как тут лучше поступить, я даже и не знаю. Очевидно, что при зацеплении двух коротких полиномов будет получаться тоже относительно короткий. С другой стороны, если его оставить, то он будет дублировать информацию, получаемую из зацеплений результатов редуцирования, то есть будет нерациональность действий. В любом случае, нельзя бездумно плодить зацепления и складировать их в очереди. Зацепления надо строить, только когда никаких других действий не осталось. При этом возникает проблема отслеживания того, какие из них уже вычислены и проверены, а до каких очередь ещё не дошла.

Так же тут вопрос со списком полиномов. Если хранить вообще все находимые полиномы, то он может раздуться до неимоверных размеров. Процесс редуцирования (и проверки на нередуцируемость) тоже станет очень медленным: пропорциональным (грубо говоря) размеру списка. Надо все эти соображения обдумать и написать новую версию алгоритма.

 
 
 
 Re: Равенство корней двух многочленов
Сообщение03.02.2026, 17:59 
B@R5uk в сообщении #1717052 писал(а):
Надо все эти соображения обдумать и написать новую версию алгоритма.
На всякий случай: Вы в курсе, что в системах компьютерной алгебры это все уже давно реализовано? И в Вашем примере базис Гребнера ненамного длиннее самой системы и состоит из коротеньких многочленов?

 
 
 
 Re: Равенство корней двух многочленов
Сообщение03.02.2026, 18:21 
Аватара пользователя
nnosipov, да в курсе.

(НЕМНОГО НЫТЬЯ)

Только где б её взять эту систему с моими мобильными интернетами, сидя в деревне, куда автобусы/маршрутки не ходят? А даже если найти доступ хороший (быстрый, безлимитный), часть этих систем коммерческие, и в большинстве под моей старой семёркой вряд ли пойдут. А другая часть — оупенсорсная под линукс, которую на винду без плясок с бубном и без определённого опыта не установить (закачка, компилирование и настройка одних только эмуляторов окружения линкукс чего стоит!) Я приглядывался к тому сэйдж, и к сингьюла тоже. Там всё одна история: поставь сначала то, да это, а потом, может, и целевая программа заработает.

Я думал, что напишу простой алгоритм, и он сможет самые простые системы пережевать. Так сказать, познакомлюсь с предметом на ощупь, пойму что к чему, и не буду просто end-user consumer. Но что-то я перемудрил с тем, что выше сделал. Совсем плохо работает.

 
 
 [ Сообщений: 29 ]  На страницу Пред.  1, 2


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group