For English Readers → FPS Composition and Compositional Inverse (Part 1)
概要
noshi91 さんにより,形式的べき級数の合成・逆関数を
これは基礎的な問題に対して簡潔なアルゴリズムで既知の計算量を改善するもので,国内・国外問わず多くの関心を集めました.
その後,合成アルゴリズムの転置原理を用いたより簡潔な導出(Elegia さん,hos_lyric さん)や,それらの定数倍の良い実装について考察(Nachia さん等)がされています.このことについて学べる記事があまりないように感じたので,私の方でもある程度解説してみることにします.(発見者等については私の認識を書いていますが,不適切な部分があれば指摘してください.)
記事 (1), (2) の 2 つに分けて解説することを予定しています.本記事 (1) では逆関数および,その計算に用いられる Power Projection のアルゴリズム・実装を扱います.記事 (2) で,転置原理を利用した合成アルゴリズムの導出や実装を扱う予定です.
次回 → FPS 合成・逆関数の解説(2)転置原理による合成アルゴリズムの導出
本記事では多項式・FPS の畳み込みが
参考文献
- https://noshi91.hatenablog.com/entry/2024/03/16/224034 (noshi91)
- https://arxiv.org/abs/2404.05177 (noshi91, Elegia)
提案手法を論文にしたもの.合成については,転置原理を使わない導出をしている. - Library Checker verify 用問題がある.
- FPS composition f(g(x)) の実装について (Nachia)
Library Checker での問題で 2024/03 時点での最速実装を達成した Nachia さんによる実装メモ.本記事の執筆に際してもかなり参考にした. - On implementing O(nlog(n)^2) algorithm of FPS composition (hly1024)
アルゴリズムの英語解説(codeforces blog). - Why is no one talking about the new fast polynomial composition algorithm? (Kapt)
アルゴリズムの英語解説(codeforces blog)
逆関数と Power Projection
このとき
が成り立ちます.
結局,逆関数を求める問題は次の計算に帰着できます:
これは,以下に解説する Power Projection と呼ばれる問題の特殊ケースです.noshi91 さんの手法は,Power Projection を
以下,Power Projection を解くアルゴリズムや,その高速な実装方法を解説します.
Power Projection のアルゴリズム
FPS のべき乗(power)の係数の適当な重みでの線形結合(projection)を列挙するという次の問題を考えます:
[Power Projection] 数列
なお本記事では,説明を簡潔にするために,以下
FPS
これを Bostan-Mori のアルゴリズム と同様の
となりますが,
が得られます.求めるべきものを考えると
これは問題の形を保ったまま
とする. となるまで次によって を定める: の について奇数次の部分を 項分取り出して とする. の について偶数次の部分を 項分取り出して とする. とする.
であるとき, は 変数 FPS の除算になっている.これの 次までを求めて出力する.
なお,
計算量を解析するために,各
上のアルゴリズムの各反復について,より詳しく見ましょう.
計算したいものの
一方で,
それはそれで統一的な扱いをする部分の次数が
アルゴリズムそのものを少し修正して次のようにします.
とする. となるまで次によって を定める: の について奇数次の部分を 項分取り出して とする. の について偶数次の部分を 項分取り出して とする. とする.
であるとき, , を reverse したもの とし(より形式的には など), の 次までを出力する.
すると,各時点で
高速化に強い関心がない場合は,ここまでの理解に基づいて実装すればよいでしょう.
実装例(1083ms):https://judge.yosupo.jp/submission/203740
上の実装例ではアルゴリズムの動作を分かりやすくするため,
実装例(1042ms):https://judge.yosupo.jp/submission/203746
Power Projection の FFT を利用した高速化 (案1)
多項式の FFT が可能であるとき,より定数倍の良い実装が可能になります.高速化手法の多くは
と共通なので,以下の議論に慣れがない場合には先にこちらの問題の高速化に取り組んでも良いかもしれません.次の資料も役に立つと思います.
各反復の開始時点で,
を 埋めして型 に拡張する. に を加える. を長さ でフーリエ変換したもの を計算する.これは各軸方向に FFT すれば計算できる. と の各点積をとったものは のフーリエ変換 である.これを逆フーリエ変換することで が求まる. も同様である.逆フーリエ変換の出力は の長さ での巡回畳み込みである.よって となるべき項が になっているのでその分を修正する必要がある.
したがって必要な計算はフーリエ変換
は から読み取れる.特にフーリエ変換を bit reverse 順に並べる実装では, の 番目・ 番目が の 番目・ 番目に一致するという簡潔な対応がある(参考記事内「 の DFT の計算」).特に実装内で を定義したりそのフーリエ変換をする必要はない.
実装例(725ms):https://judge.yosupo.jp/submission/203748
さらに参考記事内「偶数部分 (奇数部分) だけ IDFT」のテクニックにより,
実装例(586ms):https://judge.yosupo.jp/submission/203750
さらに各反復の最初と最後に注目すると,「長さ
これも FFT の総量を減らす定数倍高速化になっているはずですが,私が思ったよりも実行速度の改善は少なかったです.
実装例(574ms)https://judge.yosupo.jp/submission/203752
なお,計算は
実装例(501ms)https://judge.yosupo.jp/submission/203753
これを適当に
実装例(477ms)https://judge.yosupo.jp/submission/203754
Power Projection の FFT を利用した高速化 (案2)
本記事ではじめに紹介した実装例では,2 次元の畳み込みを 1 次元の畳み込みに帰着するという方法を紹介しました.
実装例(1042ms)https://judge.yosupo.jp/submission/203746
実装例(531ms)https://judge.yosupo.jp/submission/203785
算術演算の回数は (案1) よりも多いはずですが,ボトルネックとなる部分の処理が各反復において長さ
実装量の簡潔さとパフォーマンスの良さのどちらもまずまずで,結構良いかも.
コメント
Power Projection のアルゴリズム・実装の基本的な解説はここまでとします.私の力量や時間の都合もあり,Library Checker 最速になるほど洗練された実装を解説することはできませんでしたが,重要な考え方はおおよそ紹介できたのではないかと考えています.
ここからさらに高速化したい場合に考えられる方向性について簡単に述べます.私もすべてを実装してはいません.
- 型
の多項式を長さ で FFT する際,FFT を行う軸の順序に工夫の余地がある.
上図の通り,
次元配列のすべての列(あるいは 次元配列を 個おきに取り出したもの)に対して何かをするという計算が頻発します.FFT の実装をこうした場合に適用できるように一般化しておくと,メモリを移し替える回数が少なくなって,高速化になるかもしれません.
- この記事で紹介した実装では,
方向について常にフーリエ変換した値を持っています.さらに 方向についてもフーリエ変換した値を持つようにするという方針も考えられます.この方法も検討しましたが,私は計算量を落とすことはできませんでした(同程度にはなります).次のことができれば計算量が改善できると思いますが,難しいと思っています.
長さ
ここまでいくつかの実装を紹介しましたが,フーリエ変換の性質を上手く使った高速化をしている実装は,多項式の FFT が可能であるという係数環の性質に依存していることにも注意してください.競技プログラミングでの利用を考えている場合には,例えば 「