00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifndef __MMX_ROOT_MODULAR_HPP
00014 #define __MMX_ROOT_MODULAR_HPP
00015
00016 #include <basix/list.hpp>
00017 #include <numerix/modular_int.hpp>
00018 #include <numerix/modular_integer.hpp>
00019 #include <algebramix/modular_polynomial.hpp>
00020
00023
00024 namespace mmx {
00025
00026 #define C typename scalar_type_helper<Polynomial>::val
00027 #define TMPL template<typename Polynomial>
00028 #define Modulus_polynomial modulus<Polynomial>
00029 #define Modular_polynomial modular<Modulus_polynomial>
00030
00031 struct root_modular_naive {
00032
00033 TMPL static Polynomial
00034 pow_mod (const Polynomial& a, const integer& n, const Polynomial& f) {
00035 Modulus_polynomial _f= Modular_polynomial::get_modulus ();
00036 Modular_polynomial::set_modulus (f);
00037 Polynomial g= * binpow (Modular_polynomial (a), n);
00038 Modular_polynomial::set_modulus (_f);
00039 return g;
00040 }
00041
00042 TMPL static Polynomial
00043 degree_one_factorization (const Polynomial& f, const integer& p) {
00044
00045 Polynomial x (C(1), 1);
00046 Polynomial g= pow_mod (x, p, f) - x;
00047 return gcd (g, f);
00048 }
00049
00050 TMPL static void
00051 linear_splitting (Polynomial& g, const Polynomial& f, const integer& p) {
00052 VERIFY (f != 0, "bug");
00053 nat n= deg (f); g= f;
00054 if (n == 1) return;
00055 Polynomial x (C(1), 1);
00056 nat counter= 0;
00057 while (deg (g) <= 0 || (nat) deg (g) == n) {
00058 vector<C> _a (C (0), n);
00059 for (nat i= 0; i < n; i++) _a[i]= C(rand ());
00060 Polynomial a (_a), b;
00061 g= gcd (a, f);
00062 if (deg (g) > 0) return;
00063 g= p == 2 ? gcd (a - 1, f)
00064 : gcd (pow_mod (a, (p-1) / 2, f) - 1, f);
00065 counter++;
00066 }
00067
00068 ASSERT (deg (g) > 0 && (nat) deg (g) < n, "cannot find a linear factor"); }
00069
00070 TMPL static vector<Polynomial>
00071 linear_factorization (const Polynomial& f, const integer& p) {
00072 VERIFY (f != 0, "bug");
00073 list<Polynomial> todo (f);
00074 vector<Polynomial> factors= vec<Polynomial> ();
00075 if (deg (f) <= 0) return factors;
00076 while (!is_nil (todo)) {
00077 Polynomial h= car(todo), g; todo= cdr(todo);
00078 linear_splitting (g, h, p);
00079 if ((nat) deg (g) == 1) factors << g;
00080 else todo= cons (g, todo);
00081 if (deg (g) != deg (h)) todo= cons (h / g, todo);
00082 }
00083 return factors; }
00084
00085 TMPL static vector<C>
00086 roots (const Polynomial& f, const integer& p) {
00087 if (deg (f) <= 0) {
00088 return vector<C> ();
00089 }
00090
00091 Polynomial g= degree_one_factorization (f, p);
00092
00093 vector<Polynomial> lin_facts= linear_factorization (g, p);
00094 vector<C> b (C(), N(lin_facts));
00095 for (nat i= 0; i < N(lin_facts); i++)
00096 b[i]= - lin_facts[i][0] / lin_facts[i][1];
00097 return b; }
00098 };
00099
00100 #undef C
00101 #undef TMPL
00102 #undef Modulus_polynomial
00103 #undef Modular_polynomial
00104
00105 #define Modulus modulus<C,V>
00106 #define Modular modular<Modulus,W>
00107
00108 template<typename C, typename V, typename W> vector<Modular>
00109 separable_roots (const Modular& a, nat r) {
00110
00111 C p= * get_modulus (a);
00112 ASSERT (Modular (r) != 0, "wrong argument");
00113 polynomial<Modular> x_r (C(1),r);
00114 return root_modular_naive::roots (x_r - a, p);
00115 }
00116
00117 template<typename C, typename V, typename W> Modular
00118 separable_root (const Modular& a, nat r) {
00119
00120
00121 if (a == 1) return a;
00122 vector<Modular> ans= separable_roots (a, r);
00123 ASSERT (N (ans) != 0, "no root");
00124 return ans [0];
00125 }
00126
00127 template<typename C, typename V, typename W> vector<Modular>
00128 polynomial_modular_roots (const polynomial<Modular>& P) {
00129
00130 ASSERT (N (P) != 0, "wrong argument");
00131 return root_modular_naive::roots (P, * get_modulus (P[0]));
00132 }
00133
00134 template<typename C, typename V, typename W> Modular
00135 polynomial_modular_root (const polynomial<Modular>& P) {
00136
00137
00138 if (P[0] == Modular (0)) return Modular (0);
00139
00140 vector<Modular> ans= polynomial_modular_roots (P);
00141 polynomial<Modular> dP = derive(P);
00142 ASSERT (N (ans) != 0, "no root");
00143 for (nat i= 0; i < N(ans); i++)
00144 if (eval (dP,ans[i]) != Modular (0)) return ans[i];
00145 ERROR ("no regular root");
00146 }
00147
00148 template<typename C, typename V, typename W> inline Modular
00149 pth_root (const Modular& a) {
00150
00151 return a;
00152 }
00153
00154
00155
00156 template<typename C, typename V, typename W> vector<Modular>
00157 nth_roots (const Modular& a, nat r) {
00158
00159 C p= * get_modulus (a);
00160 if (Modular (r) == 0) return nth_roots (a, r / as<nat> (p));
00161 return separable_roots (a, r);
00162 }
00163
00164 template<typename C, typename V, typename W> Modular
00165 nth_root (const Modular& a, nat r) {
00166 if (a == 1) return a;
00167 vector<Modular> ans= nth_roots (a, r);
00168 ASSERT (N (ans) != 0, "no root");
00169 return ans [0];
00170 }
00171 #undef Modulus
00172 #undef Modular
00173 }
00174 #endif // __MMX_ROOT_MODULAR_HPP