intalg.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002     
00003     intalg.cpp -- Описание см. в файле intalg.hpp.
00004 
00005     Этот файл является частью библиотеки Arageli.
00006 
00007     Some functions in this file are part of Anna Bestaeva degree work 2006.
00008     They have been integrated into Arageli by Sergey Lyalin.
00009 
00010     Copyright (C) Nikolai Yu. Zolotykh, 1999--2006
00011     Copyright (C) Sergey S. Lyalin, 2005
00012     Copyright (C) Aleksey A. Bader, 2005--2006
00013     Copyright (C) Anna Bestaeva, 2006
00014     
00015     University of Nizhni Novgorod, Russia
00016 
00017 *****************************************************************************/
00018 
00019 #include "config.hpp"
00020 
00021 #if !defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE) || \
00022     defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE_INTALG)
00023 
00024 #include "intalg.hpp"
00025 #include "powerest.hpp"
00026 #include "vector.hpp"
00027 
00028 
00029 namespace Arageli
00030 {
00031 
00032 
00033 template <typename T, typename T_factory>
00034 std::size_t nbits (T a, const T_factory& tfctr)
00035 {
00036     std::size_t res = tfctr.null(a);
00037     std::size_t n = a;
00038     while(n)
00039     {
00040         ++res;
00041         n >>= 1;
00042     }
00043     return res;
00044 }
00045 
00046 
00047 template <typename T, typename I, typename T_factory>
00048 T power_mod (T a, I n, const T& m, const T_factory& tfctr)
00049 {
00050     ARAGELI_ASSERT_0(!is_null(a) || is_positive(n));
00051     
00052     T res = tfctr.unit(a);
00053     while(!is_null(n))
00054     {
00055         if(is_odd(n))(res *= a) %= m;
00056         (a *= a) %= m;
00057         n >>= 1;
00058     }
00059     
00060     return res;
00061 }
00062 
00063 
00064 namespace _Internal
00065 {
00066 
00067 template <typename T, typename V>
00068 T conditioner (const T& _a, const T& _b, const T& N, V &d)
00069 {
00070     typedef unsigned long index;
00071     
00072     typename V::template other_element_type<T>::type a(d.size()), b(d.size());
00073     index t, K = 2*std::pow(nbits(N), 1.5);
00074     typename V::template other_element_type<bool>::type B(K + 1, true);
00075 
00076     for(std::size_t i = 0; i < d.size(); i ++)
00077     {
00078         a[i] = prrem(_a, d[i]);
00079         b[i] = prrem(_b, d[i]);
00080         T gi = gcd(b[i], d[i]);
00081 
00082         if(gi > unit<T>() && gi < d[i])
00083         {  d[i] /= gi;
00084             d.insert(d.begin() + i, gi);
00085             return opposite_unit<T>();//-1;
00086         }
00087     }
00088 
00089     for(std::size_t i = 0; i < d.size(); i ++)if(!is_null(b[i])) 
00090     {
00091         T si = mod(-a[i], b[i], d[i]);
00092         if(K < si) continue;     
00093         index M = index(si);
00094 
00095         for(;;)
00096         {
00097             B[M] = false;
00098             if(M + d[i] > K) break;
00099             M += index(d[i]);
00100         }
00101     }
00102 
00103     for(t = 0; t < B.size(); t++)if(B[t])break;
00104     
00105     for(std::size_t i = 0; i < d.size(); i ++)
00106     {
00107         T gi = gcd(a[i] + t*b[i], d[i]);
00108         
00109         if(gi > unit<T>())
00110         {
00111             d[i] /= gi;
00112             d.insert(d.begin() + i, gi);
00113             return opposite_unit<T>();//-1;
00114         }
00115     }
00116 
00117     return t;
00118 }
00119 
00120 
00121 template <typename T>
00122 T conditioner (const T& a, const T& b, const T& N)
00123 { 
00124     ARAGELI_ASSERT_0(is_unit(gcd(a, b)));
00125     ARAGELI_ASSERT_0(is_positive(N));
00126 
00127     vector<T> d(1, N);
00128     T c;
00129 
00130     do
00131     {
00132         c = conditioner(a, b, N, d);
00133     }while(is_opposite_unit(c));
00134 
00135     ARAGELI_ASSERT_1(is_unit(gcd3(a, b, N) == gcd(a + c*b, N)));
00136 
00137     return c;
00138 }
00139 
00140 
00141 }   // namespace _Internal
00142 
00143 
00144 template <typename T1, typename T2, typename T3>
00145 T3 div_mod (const T1& a, const T2& b, const T3& d)
00146 {
00147     // WARNING! Are all variables of type T3.
00148     T3 u, v, g = euclid_bezout(b, d, u, v);
00149     return mod(u*a/g, d);
00150 }
00151 
00152 
00153 template <typename T1, typename T2, typename T3>
00154 T3 quo_mod (const T1& a, const T2& b, const T3& d)
00155 {
00156     T3 r = rem_mod(a, b, d);
00157     T3 c = div_mod(a - r, b, d);
00158     return mod(c, d);
00159 }
00160 
00161 
00162 template <typename T>
00163 T split (const T& a, const T& d)
00164 {
00165     T x = a, t = d;
00166     
00167     while(!is_unit(x))
00168     {
00169         x = gcd(x, t);
00170         t /= x;
00171     }
00172 
00173     return t;
00174 }
00175 
00176 
00177 template <typename T>
00178 T stab (const T& A, const T& B, const T& N)
00179 {
00180     ARAGELI_ASSERT_0(is_positive(N));
00181 
00182     if(is_null(B))return null(A);
00183     if(is_null(A))return unit(A);
00184 
00185     T   c,
00186         g1 = gcd3(A, B, N),
00187         g2 = gcd(A/g1, B/g1),
00188         a = A/(g1*g2),
00189         b = B/(g1*g2),
00190         d = N/g1;
00191 
00192     if(is_unit(gcd(a, d)))
00193         return null(A);
00194     if(is_unit(gcd(a + b, d)))
00195         return unit(A);
00196 
00197     c = _Internal::conditioner(a, b, d);
00198 
00199     ARAGELI_ASSERT_1(gcd3(A, B, N) == gcd(A + c*B, N));
00200 
00201     return c;
00202 }
00203 
00204 
00205 template <typename T>
00206 T unit (const T& a, const T& N)
00207 {
00208     ARAGELI_ASSERT_0(is_positive(N));
00209 
00210     T   u, v, w, z,
00211         g = gcdex(a, N, u, v, w, z),
00212         c = mod(u + stab(u, w, N)*w, N);
00213 
00214     ARAGELI_ASSERT_1(is_unit(gcd(c, N)));
00215     // std::cout<<"\na = "<<a<<"\nN = "<<N<<"\nc = "<<c
00216     //   <<"\nmod(c*a, N) = "<<mod(c*a, N)<<"\ngcd(a, N) = "<<gcd(a, N);
00217     ARAGELI_ASSERT_1(mod(c*a, N) == mod(gcd(a, N), N));
00218 
00219     return c;
00220 }
00221 
00222 
00223 template <typename T>
00224 T split_stab (const T& A, const T& B, const T& N)
00225 {
00226     ARAGELI_ASSERT_0(is_positive(N));
00227 
00228     if(is_null(B))return null(A);
00229     if(is_null(A))return unit(A);
00230 
00231     T   c,
00232         g1 = gcd(A, B, N),
00233         g2 = gcd(A/g1, B/g1),
00234         a = A/(g1*g2),
00235         b = B/(g1*g2),
00236         d = N/g1;
00237 
00238     if(is_unit(gcd(a, d)))
00239         return null(A);
00240     if(is_unit(gcd(a + b, d)))
00241         return unit(A);
00242 
00243     c = split(a, d);
00244 
00245     ARAGELI_ASSERT_1(gcd3(A, B, N) == gcd(A + c*B, N));
00246 
00247     return c;
00248 }
00249 
00250 
00251 template <typename T>
00252 T split_mod (const T& a, const T& d)
00253 {
00254     // WARNING! Need to create nnbits(x) function to compute nbits(nbits(x)).
00255 
00256     std::size_t N = nbits(nbits(a))/*(big_int(a.length())).length()*/;
00257     T x = a;
00258     for(std::size_t i = 0; i <= N + 1; i++) //??? i <= loglogN ???// WARNING!
00259         x = mod(x*x, d);
00260     return d/gcd(x, d);
00261 }
00262 
00263 
00264 template <typename T>
00265 T stab_mod (const T& a, const T& b, const T& N)
00266 { 
00267     ARAGELI_ASSERT_0(is_positive(N));
00268 
00269     if(is_null(b)) return null<T>();
00270     if(is_null(a)) return unit<T>();
00271     T g = gcd3(a, b, N),
00272     c = split_mod(a/g, N/g);
00273 
00274     ARAGELI_ASSERT_1(gcd3(a, b, N) == gcd(a + c*b, N));
00275 
00276     return c;
00277 }
00278 
00279 
00280 template<typename T>
00281 bool is_invertible_mod (const T& a, const T& N)
00282 { return is_unit(gcd(mod(a, N), N)); }
00283 
00284 
00285 template <typename T, typename T_factory>
00286 T factorial_successive_multiplication (T a, const T_factory& tfctr)
00287 {
00288     ARAGELI_ASSERT_0(sign(a, tfctr) >= 0);
00289 
00290     if(is_null(a) || is_unit(a))return tfctr.unit(a);
00291     T res = a;
00292 
00293     for(--a; !is_unit(a); --a)
00294         res *= a;
00295 
00296     //T res = T(1);
00297     //for(T i = T(2); i <= a; ++i)
00298     //  res *= i;
00299 
00300     return res;
00301 }
00302 
00303 
00304 template <typename T, typename T_factory>
00305 T factorial_even_odd_multiplication (T a, const T_factory& tfctr)
00306 {
00307     //return factorial_successive_multiplication(a, tt);
00308     
00309     ARAGELI_ASSERT_0(sign(a) >= 0);
00310 
00311     if(is_null(a) || is_unit(a))return tfctr.unit(a);
00312     T unit = tfctr.unit(a), two = unit; ++two;
00313     if(a == two)return two;
00314     
00315     T res = unit;
00316     T n2q, n2r, n4q, n4r;
00317     divide(a - unit, two, n2q, n2r);
00318     divide(n2q - unit, two, n4q, n4r);
00319 
00320     if(!is_null(n2r))res *= a;
00321     if(!is_null(n4r))res *= n2q;
00322 
00323     res *= factorial_even_odd_multiplication(n4q, tfctr);
00324 
00325     T t = unit;
00326     T iend = (n4q << 1u) + unit;
00327     T i = (n2q << 1u) + unit;
00328     for(; i != iend; ----i)
00329         t *= i;
00330 
00331     T t1 = unit;
00332     for(; !is_unit(i); ----i)
00333         t1 *= i;
00334 
00335     return (res*t)*(t1*t1) << (n2q + n4q);
00336 }
00337 
00338 
00339 template <typename T, typename T_factory>
00340 int jacobi (T n, T p, const T_factory& tfctr)
00341 {
00342     ARAGELI_ASSERT_0(is_positive(p));
00343     ARAGELI_ASSERT_0(is_odd(p));
00344 
00346 
00347     T g;
00348     T a = n;
00349     T b = p;
00350 
00351     //if (!(b % 2)) return 2;
00352     if (a >= b) a = a%b;
00353     if (a == 0) return 0;
00354     if (a == 1) return 1;
00355 
00356     if (a < 0)
00357         if ((b-1)/2 % 2 == 0)
00358             return jacobi(-a,b);
00359         else 
00360             return -jacobi(-a,b);
00361 
00362     if (a % 2 == 0)
00363         if (((b*b - 1)/8) % 2 == 0)
00364             return +jacobi(a/2,b);
00365         else 
00366             return -jacobi(a/2,b);
00367 
00368     g = gcd(a, b);
00369     //if (!(a % 2)) return 2;
00370 
00371     if (g == a)return 0;
00372     else
00373         if (g != 1)
00374             return jacobi(g,b)*jacobi(a/g,b);
00375         else
00376             if (((a-1)*(b-1)/4) % 2 == 0)
00377                 return +jacobi(b,a);
00378             else
00379                 return -jacobi(b,a);
00380 
00381 
00383 
00384     //ARAGELI_ASSERT_0(is_positive(n));
00385     //ARAGELI_ASSERT_0(is_odd(n));
00386 
00387     //if(is_divisible(a, n))return tfctr.null(a);
00388 
00389     //int res = 1;
00390 
00391     //if(is_negative(a))
00392     //{
00393     //  if(is_odd((n - 1) >> 1))res = -res;
00394     //  opposite(&a);
00395     //}
00396 
00397     //if(a > n)a %= n;
00398 
00399     //T a1, t;
00400     //
00401     //for(;;)
00402     //{
00403     //  factorize_multiplier(a, 2, a1, t);
00404 
00405     //  if(is_odd((t*t - 1) >> 3))res = -res;
00406 
00407     //  if(is_unit(a1))break;
00408 
00409     //  ARAGELI_ASSERT_1(a1 < n);
00410     //  ARAGELI_ASSERT_1(a1 > tfctr.unit(a1));
00411 
00412     //  if(is_odd(((a1 - 1) >> 1) * ((n - 1) >> 1)))res = -res;
00413 
00414     //  a = n; n = a1;
00415     //  ARAGELI_ASSERT_1(a > n);        
00416     //  a %= n;
00417     //}
00418 
00419     //return res;
00420 }
00421 
00422 
00423 template <typename T>
00424 T intsqrt (const T& a)
00425 {
00426     ARAGELI_ASSERT_1(sign(a) >= 0);
00427     if(is_null(a) || is_unit(a))return a;
00428 
00429     T r = a >> 1;
00430     T q;
00431     for(;;)
00432     {
00433         q = a / r;
00434         if(q >= r)break;
00435         else r = (r + q) >> 1;
00436     }
00437 
00438     ARAGELI_ASSERT_1(r*r <= a && (r+1)*(r+1) > a);
00439     return r;
00440 }
00441 
00442 
00443 template <typename T, typename TT>
00444 T sqrt_mod_shenks (const T& a, const T& n, const TT& tt)
00445 {
00446     ARAGELI_ASSERT_0(is_positive(a));
00447     ARAGELI_ASSERT_0(is_positive(n));
00448     ARAGELI_ASSERT_0(a < n);
00449     ARAGELI_ASSERT_0(is_prime(n));
00450     ARAGELI_ASSERT_0(jacobi(a, n) == 1);
00451     ARAGELI_ASSERT_0(is_unit(n%4));
00452 
00454     
00455 //  ARAGELI_ASSERT_ALWAYS(0);
00456     T b, j, r;
00457     T p = 2;
00458     for(;jacobi(p, n)>-1;p+=1);
00459     T temp = (n-1)/2;
00460     unsigned alpha = 1;
00461     while (!(temp % 2))
00462     {
00463         temp = temp /2;
00464         ++alpha;
00465     }
00466     T s = temp;
00467     r = power_mod(a, (s+1)/2, n);
00468     b = power_mod(p, s, n);
00469 //      find inverse element a^(-1)
00470     T inva = inverse_mod(a, n);
00471     T temp1 = (r*r*inva) % n;
00472     j = "0";
00473     const T two = "2";
00474     T t1 = power(two, alpha - two);
00475     if (is_null(power_mod(temp1, t1, n) - n-1)) j=1;
00476     int i;
00477     T t2;
00478     for (i = 1; i <= alpha - 2; ++i)
00479     {
00480         j*=2;
00481         t2 = power(two, alpha-i-two);
00482         if (is_null(power_mod(r*r*inva*b*b, t2, n) - n-1))
00483         {
00484             j++;
00485         }
00486     }
00487     return power(b,j)*r%n;
00488 }
00489 
00490 
00492 
00493 //template <typename T>
00494 //T sqrt_mod (const T& a, const T& n, const TT& tt)
00495 //{
00496 //  ARAGELI_ASSERT_0(is_positive(a, tt));
00497 //  ARAGELI_ASSERT_0(is_positive(n, tt));
00498 //  ARAGELI_ASSERT_0(a < n);
00499 //  ARAGELI_ASSERT_0(is_prime(n, tt));
00500 //  AEAGELI_ASSERT_0(jacobi(a, n, tt) == 1);
00501 //
00502 //  if(n == 2)
00503 //  {
00504 //      AEAGELI_ASSERT_1(tt.is_unit(a) || tt.is_null(a));
00505 //      return a;
00506 //  }
00507 //  
00508 //  /////////  WARNING! PARTIAL IMPLEMENTATION!  //////////
00509 //  ARAGELI_ASSERT_ALWAYS(n%4 == 3);
00510 //
00511 //  AEAGELI_ASSERT_1(is_divisible(n+1, 4, tt, type_traits<int>()));
00512 //  return power_mod(a, (n+1)/4, tt);
00513 //}
00514 //
00516 
00517 
00518 } // namespace Arageli
00519 
00520 #endif
00521 

Generated on Thu Aug 31 17:38:06 2006 for Arageli by  doxygen 1.4.7