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