sqfr ..... 無平方因子に分解する

関数の名称 sqfr は square free(無平方)に由良するが、square free 因子を出力するわけではなく、多項式を平方因子を含まない項に因数分解する。factor との違いを見てみる分かりやすい。

(%i1) expand((x - 1)^3 * (x + 1)^3 * (x + 2));

             7      6      5      4      3      2
(%o1)       x  + 2 x  - 3 x  - 6 x  + 3 x  + 6 x  - x - 2


(%i2) sqfr(%o1);

                                    2     3
(%o2)                     (x + 2) (x  - 1)


(%i3) factor(%o1);

                             3        3
(%o3)                 (x - 1)  (x + 1)  (x + 2)
つまり、sqfr を実行した場合は x2 - 1(square free)は因数分解されずに残る。このような関数が用意されている理由は、一般に因数分解は困難であるが、square free 因子を見つけることは簡単だからである。

以下、参考までに square free 因子を見つける実験してみましょう。まず、関数 f[1] とその導関数 f'[1] との最大公約数 f[2] を求めます。さらに、f[2] と f'[2] の最大公約数 f[3] を求め .....、という作業を最大公約数が 1 になるまで実行します:

(%i1) f[1]: expand((x - 1)^3 * (x + 1)^3 * (x + 2));

             7      6      5      4      3      2
(%o1)       x  + 2 x  - 3 x  - 6 x  + 3 x  + 6 x  - x - 2


(%i2) f[2]: gcd(f[1], diff(f[1], x));

                             4      2
(%o2)                       x  - 2 x  + 1


(%i3) f[3]: gcd(f[2], diff(f[2], x));

                                2
(%o3)                          x  - 1


(%i4) f[4]: gcd(f[3], diff(f[3], x));

(%o4)                             1
1 になる 1 つ手前 f[3] = x2 - 1 に注目します。一連の計算から、f[2] は x2 - 1 の 2 乗で割り切れ、f[1] は x2 - 1 の 3 乗で割り切れると分かります。そこで、
(%i6) quotient(f[2], f[3]^2);

(%o6)                             1


(%i5) quotient(f[1], f[3]^3);

(%o5)                           x + 2
をあわせて、求める square free 因子は x2 - 1 と x + 2 と分かります。もう一例、分かりやすそうなのを書いておきます。
(%i6) f[1]: expand(x^5 * (x + 1)^2 * (x - 1)^2 * (x + 4));

                 10      9      8      7    6      5
(%o6)           x   + 4 x  - 2 x  - 8 x  + x  + 4 x


(%i7) f[2]: gcd(f[1], diff(f[1], x));

                                6    4
(%o7)                          x  - x


(%i8) f[3]: gcd(f[2], diff(f[2], x));

                                  3
(%o8)                            x


(%i9) f[4]: gcd(f[3], diff(f[3], x));

                                  2
(%o9)                            x


(%i10) f[5]: gcd(f[4], diff(f[4], x));

(%o10)                            x


(%i11) f[6]: gcd(f[5], diff(f[5], x));

(%o11)                            1
ここまでで、square free 因子の 1 つが f[5] = x であり、しかも f[1] が f[5] の 5 乗で割り切れることが分かります。さらに、
(%i12) quotient(f[2], f[5]^4);

                                2
(%o12)                         x  - 1


(%i13) quotient(f[1], %^2 * f[5]^5);

(%o13)                          x + 4
により、f[1] の残りの square free 因子として、x2 - 1 と x + 4 が求まりました。最後に念のため確認しておきます:
(%i14) sqfr(f[1]);

                         5           2     2
(%o14)                  x  (x + 4) (x  - 1)

[専門的な文献]:

Mark van Hoeij, Factoring polynomials and the knapsack problem (2002)

整数係数多項式の因数分解法としては、指数時間アルゴリズムではあるけれども多くの場合実用的な Berlekamp-Zassenhaus 法と多項式時間アルゴリズムではあるけれど遅い LLL 法が良く知られている。この論文では Berlekamp-Zassenhaus 法を改良し、実用的な多項式時間アルゴリズムが考案されています。すでに Maple などにはこの方法が実装されているそうです(が、我々が日常的に扱う多項式ではその恩恵を受けることは無いでしょう)。関数 sqfr はこういったアルゴリズムを実装するためのスタート地点に相当するものです。