Лучший алгоритм для расширения рядов функции Rational

79
9

Мне нужно закодировать функцию в С++, которая эффективно находит коэффициенты ряда Тейлора данной рациональной функции (P (x)/Q (x)).


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


Моя идея была следующей.
Рассмотрим тождество


P(x) / Q(x) = R(x) + ...

Где R(x) - многочлен с числом членов, равным числу коэффициентов, которые мне нужно найти. Тогда я могу умножить обе стороны на Q(x) и получить


P(x) = R(x) * Q(x)

R(x) * Q(x) - P(x) = 0


Следовательно, все коэффициенты должны быть равны нулю. Это система уравнений, для которой необходимо решить алгоритм O (n ^ 3). O (n ^ 3) не так быстро, как я хотел.


Есть ли более быстрый алгоритм?


Я знаю, что коэффициенты рядов удовлетворяют линейному рекуррентному соотношению.
Это заставляет меня думать, что возможен алгоритм O (n).

спросил(а) 2014-04-15T22:19:00+04:00 5 лет, 7 месяцев назад
3
Решение
77

Алгоритм, который я собираюсь описать, математически обоснован формальной степенной серией. Каждая функция с рядом Тейлора имеет формальный степенной ряд. Обратное неверно, но если мы выполняем арифметику на функциях с рядами Тейлора и получаем функцию с рядом Тейлора, то мы можем выполнить ту же арифметику с формальными степенными рядами и получить тот же ответ.


Алгоритм длинного деления для формальных степенных рядов подобен алгоритму long division, который вы, возможно, узнали в школе. Я продемонстрирую его на примере (1 + 2 x)/(1 - x - x^2), который имеет коэффициенты, равные номерам Лукаса.


Знаменатель должен иметь ненулевой постоянный член. Начнем с написания числителя, который является первым остатком.


             --------
1 - x - x^2 ) 1 + 2 x

[
Разделим остаточный член младшего порядка (1) постоянным членом знаменателя (1) и положим фактор вверх.


              1
--------
1 - x - x^2 ) 1 + 2 x

Теперь умножим 1 - x - x^2 на 1 и вычтем его из текущего остатка.


              1
--------
1 - x - x^2 ) 1 + 2 x
1 - x - x^2
-------------
3 x + x^2

Сделайте это снова.


              1 + 3 x
--------
1 - x - x^2 ) 1 + 2 x
1 - x - x^2
---------------
3 x + x^2
3 x - 3 x^2 - 3 x^3
-------------------
4 x^2 + 3 x^3

И снова.


              1 + 3 x + 4 x^2
----------------
1 - x - x^2 ) 1 + 2 x
1 - x - x^2
---------------
3 x + x^2
3 x - 3 x^2 - 3 x^3
-------------------
4 x^2 + 3 x^3
4 x^2 - 4 x^3 - 4 x^4
---------------------
7 x^3 + 4 x^4

И снова.


              1 + 3 x + 4 x^2 + 7 x^3
------------------------
1 - x - x^2 ) 1 + 2 x
1 - x - x^2
---------------
3 x + x^2
3 x - 3 x^2 - 3 x^3
-------------------
4 x^2 + 3 x^3
4 x^2 - 4 x^3 - 4 x^4
---------------------
7 x^3 + 4 x^4
7 x^3 - 7 x^4 - 7 x^4
---------------------
11 x^4 + 7 x^5

Отдельные деления были скучными, потому что я использовал делитель с ведущим 1, но если бы я использовал, скажем, 2 - 2 x - 2 x^2, то все коэффициенты в частном случае разделились бы на 2.

ответил(а) 2014-04-15T23:24:00+04:00 5 лет, 7 месяцев назад
Еще 2 ответа
45

Это можно сделать в O(n log n) для произвольных P и Q степени n. Точнее это можно сделать в M(n), где M(n) - сложность полиномиального умножения, которое само может быть сделано в O(n log n).


Первое из первых членов n разложения в ряд можно рассматривать просто как многочлен степени n-1.


Предположим, вас интересуют первые члены n разложения в ряд из P(x)/Q(x). Существует алгоритм, который будет вычислять обратное к Q в M(n) времени, как определено выше.


Обратная T(x) of Q(x) удовлетворяет T(x) * Q(x) = 1 + O(x^N). То есть T(x) * Q(x) - это точно 1 плюс некоторый член ошибки, коэфициенты которого все идут после первых n терминов, которые нас интересуют, поэтому мы можем просто отказаться от них.


Теперь P(x) / Q(x) является просто P(x) * T(x), который является просто еще одним многочленом.


Вы можете найти реализацию, которая вычисляет вышеупомянутый обратный в моей библиотеке с открытым исходным кодом Altruct. Смотрите файл series.h. Предполагая, что у вас уже есть метод, который вычисляет произведение двух многочленов, код, который вычисляет обратный, составляет около 10 строк (вариант divide-and-завоевания).

Фактический алгоритм выглядит следующим образом:
Предположим Q(x) = 1 + a1*x + a2*x^2 + .... Если a0 не 1, вы можете просто разделить Q(x), а затем его обратный T(x) на a0.
Предположим, что на каждом шаге у вас есть L члены обратного так, что Q(x) * T_L(x) = 1 + x^L * E_L(x) для некоторой ошибки E_L(x). Первоначально T_1(X) = 1. Если вы включите это в вышесказанное, вы получите Q(x) * T_1(x) = Q(x) = 1 + x^1 * E_1(x) для некоторого E_1(x), что означает, что это выполняется для L=1. Пусть теперь на каждом шаге дважды L. Вы можете получить E_L(x) с предыдущего шага как E_L(x) = (Q(x) * T_L(x) - 1) / x^L или по реализации, просто отбросьте первые L коэффициенты продукта. Затем вы можете вычислить T_2L(x) с предыдущего шага как T_2L(x) = T_L(x) - x^L * E_L(x) * T_L(x). Ошибка будет E_2L(x) = - E_L(x)^2. Теперь проверим, что выполняется шаг индукции.


Q(x) * T_2L(x)
= Q(x) * (T_L(x) - x^L * E_L(x) * T_L(x))
= Q(x) * T_L(x) * (1 - x^L * E_L(x))
= (1 + x^L * E_L(x)) * (1 - x^L * E_L(x))
= 1^2 - (x^L * E_L(x))^2
= 1 + x^2L * E_2L(x)

Q.E.D.


Я уверен, что невозможно вычислить многочленное деление более эффективно, чем умножение, и, как вы можете видеть в следующей таблице, этот алгоритм всего в 3 раза медленнее, чем одно умножение:


   n      mul        inv      factor
10^4 24 ms 80 ms 3,33x
10^5 318 ms 950 ms 2,99x
10^6 4.162 ms 12.258 ms 2,95x
10^7 101.119 ms 294.894 ms 2,92x

ответил(а) 2016-10-25T02:43:00+03:00 3 года, 1 месяц назад
47

Если вы внимательно посмотрите на систему, которую вы получите с вашим планом, вы увидите, что она уже диагональна и не требует решения O (n ^ 3). Он просто вырождается в линейную рекурсию (P [], Q [] и R [] являются коэффициентами соответствующих полиномов):


R[0] = P[0]/Q[0]
R[n] = (P[n] - sum{0..n-1}(R[i] * Q[n-i]))/Q[0]

Так как Q является многочленом, сумма имеет не более чем deg(Q) членов (таким образом, вычисляя постоянное время), делая общую сложность асимптотически линейной. Вы также можете посмотреть на матричное представление рекурсии для (возможно) лучшей асимптотики.

ответил(а) 2014-04-16T01:21:00+04:00 5 лет, 7 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема