mihaild

numbers theory

Dec 6th, 2011
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.51 KB | None | 0 0
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. #
  4. #    This program is free software: you can redistribute it and/or modify
  5. #    it under the terms of the GNU General Public License as published by
  6. #    the Free Software Foundation, either version 3 of the License, or
  7. #    (at your option) any later version.
  8. #    
  9. #    This program is distributed in the hope that it will be useful,
  10. #    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. #    GNU General Public License for more details.
  13. #    
  14. #    You should have received a copy of the GNU General Public License
  15. #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16.  
  17. from collections import Counter
  18. from sys import stdin, stdout, stderr
  19. from math import sqrt
  20.  
  21. def is_prime(n):
  22.     return not any(map(lambda i: not n % i, range(2, n)))
  23.  
  24. def gcd(a, b, inform = True):
  25.     if inform:
  26.         stdout.write('gcd(%d, %d) = ' % (a, b, ))
  27.     while b:
  28.         if inform:
  29.             stdout.write('gcd(%d, %d) = ' % (b, a % b, ))
  30.         a, b = b, a % b
  31.     if inform:
  32.         print a
  33.     return a
  34.  
  35. def bit_form(n):
  36.     if not n:
  37.         return []
  38.     if n % 2:
  39.         return [1] + map(lambda x: x*2, bit_form(n / 2))
  40.     else:
  41.         return map(lambda x: x*2, bit_form(n / 2))
  42.  
  43. def factorization(n):
  44.     _n = n
  45.     factors = Counter()
  46.     i = 2
  47.     while n > 1 and i*i <= n:
  48.         if n % i:
  49.             i += 1
  50.         else:
  51.             n /= i
  52.             factors.update([i])
  53.     if n > 1:
  54.         factors.update([n])
  55.     print '%d = %s' % (_n, ' * '.join(map(lambda factor: '%d^%d' % (factor, factors[factor], ), factors)))
  56.     return factors
  57.  
  58. def fast_pow_mod(a, b, p):
  59.     print 'Считаем %d^%d по модулю %d' % (a, b, p, )
  60.     deg = 2
  61.     prev = a
  62.     while deg <= b:
  63.         print '%d^%d ≡ %d*%d ≡ %d ≡ %d' % (a, deg, prev, prev, prev*prev, prev*prev % p, )
  64.         prev = prev*prev % p
  65.         deg *= 2
  66.     bits = bit_form(b)
  67.     print '%d = %s' % (b, '+'.join(map(str, bits)))
  68.     stdout.write('%d^%d = %s' % (a, b, ' * '.join(map(lambda b: '%d^%d' % (a, b), bits))))
  69.     cur = 1
  70.     while bits:
  71.         cur *= a**bits[0] % p
  72.         del bits[0]
  73.         stdout.write(' = %s' % (' * '.join([str(cur)] + map(lambda b: '%d^%d' % (a, b), bits))))
  74.         if cur != cur % p:
  75.             cur %= p
  76.             stdout.write(' = %s' % (' * '.join([str(cur)] + map(lambda b: '%d^%d' % (a, b), bits))))
  77.     print
  78.     return cur
  79.    
  80. def phi(n):
  81.     print 'Ищем φ(%d)' % (n, )
  82.     factors = factorization(n)
  83.     res = 1
  84.     for f in factors:
  85.         c = f**(factors[f]-1) * (f - 1)
  86.         res *= c
  87.         print 'φ(%d^%d) = %d' % (f, factors[f], c, )
  88.     print 'φ(%d) = %d' % (n, res, )
  89.     return res
  90.  
  91. def primitive_root(p, k):
  92.     print 'Ищем примитивный корень в Z_{%d^%d}' % (p, k, )
  93.     def primitive_root_p(p):
  94.         print 'Ищем примитивный корень в Z_%d' % (p, )
  95.         print 'φ(%d) = %d' % (p, p-1, )
  96.         factors = factorization(p-1)
  97.         print 'Простые делители %d: %s' % (p-1, ', '.join(map(str, factors)), )
  98.         check_degs = map(lambda n: (p-1) / n, factors)
  99.         print 'Надо проверять степени %s' % (', '.join(map(str, check_degs)), )
  100.         for candidate in range(2, p):
  101.             if any(map(lambda deg: candidate**deg % p == 1, check_degs)):
  102.                 continue
  103.             print 'Проверяем %d' % (candidate, )
  104.             for deg in check_degs:
  105.                 if fast_pow_mod(candidate, deg, p) == 1:
  106.                     continue
  107.             print '%d - примитивный корень по модулю %d' % (candidate, p, )
  108.             return candidate
  109.  
  110.     p_pr = primitive_root_p(p)
  111.     if k == 1:
  112.         return p_pr
  113.     print 'Проверим, является ли %d примитивным корнем по модулю %d^2' % (p_pr, p, )
  114.     if fast_pow_mod(p_pr, p-1, p*p) != 1:
  115.         print '%d - примитивный корень mod %d^2 (а значит, и %d^%d)' % (p_pr, p, p, k, )
  116.         return p_pr
  117.     else:
  118.         print '%d не подошел; значит, %d -  примитивный корень mod %d^2 (а значит, и %d^%d)' % (p_pr, p_pr+p, p, p, k, )
  119.         return p_pr + p
  120.  
  121. def solve_congruence_modulo(k1, m1, k2, m2):
  122.     print 'Решаем сравнение: x ≡ %d (%d), x ≡ %d (%d)' % (k1, m1, k2, m2, )
  123.     cur = k1
  124.     while cur % m2 != k2:
  125.         #print '%d mod %d == %d; не подходит' % (cur, m2, cur % m2, )
  126.         cur += m1
  127.     print '%d + %d*%d = %d ≡ %d (%d); подходит' % (k1, m1, (cur - k1)/m1, cur, cur % m2, m2, )
  128.     return cur
  129.  
  130. def group_decomposition(m):
  131.     print 'Разложение группы Z_{%d}^*' % (m, )
  132.     factors = factorization(m)
  133.     print
  134.     g = {}
  135.     r = {}
  136.     if 2 in factors:
  137.         if factors[2] == 1:
  138.             r[-1] = 1
  139.             r[0] = 1
  140.         else:
  141.             r[-1] = 2
  142.             r[0] = 2**(factors[2] - 2)
  143.         print 'Ищем примитивные корни для 2^%d' % (factors[2], )
  144.         g[-1] = solve_congruence_modulo(-1, 2**factors[2], 1, m / 2**factors[2])
  145.         g[0] = solve_congruence_modulo(5, 2**factors[2], 1, m / 2**factors[2])
  146.         print
  147.     i = 0
  148.     for factor in factors:
  149.         if factor != 2:
  150.             i += 1
  151.             f = factor**factors[factor]
  152.             r[i] = phi(f)
  153.             g[i] = solve_congruence_modulo(primitive_root(factor, factors[factor]), f, 1, m/f)
  154.             print
  155.     print ('Z_{%d}^* = ' % (m, )) + ' * '.join(map(lambda i: '<%d>_{%d}' % (g[i], r[i], ), sorted(g.keys())))
  156.  
  157. def sqr_solves_count(a, b, c, m):
  158.     print 'Проверяем, сколько решений имеет сравнение %d*x^2 + %d*x + %d ≡ 0 (mod %d)' % (a, b, c, m, )
  159.     if not m % 2 and b % 2:
  160.         print 'b делится на 2, m - нет. Не знаю, что делать'
  161.         return None
  162.     factors = factorization(m)
  163.     d = (b*b - 4*a*c)# % m
  164.     print 'Дискриминант равен %d' % (d, )
  165.     for factor in factors:
  166.         if factors[factor] >= 2 and not d % factor:
  167.             print 'Дискриминант делится на %d, которое входит в %d в степени выше первой. Не знаю, что делать' % (factor, m, )
  168.             return None
  169.     for factor in factors:
  170.         if factor != 2:
  171.             if (d**((factor-1)/2) + 1) % factor == 0:
  172.                 p = fast_pow_mod(d, (factor - 1) / 2, factor)
  173.                 print '%d - не квадратичный вычет по модулю %d, решений нет' % (d, factor, )
  174.                 return 0
  175.     res = 1
  176.     if 2 in factors:
  177.         if factors[2] > 2:
  178.             if d % 8 == 1:
  179.                 print 'По модулю %d есть 4 решения' % (2**factors[2], )
  180.                 res *= 4
  181.             else:
  182.                 print 'А вот нету решений по модулю %d, пичалька:(' % (2**factors[2], )
  183.                 return 0
  184.         else:
  185.             print 'Хм, модуль делится на 2, но не делится на 8. ХЗ что делать'
  186.             return None
  187.     for factor in factors:
  188.         if factor != 2:
  189.             if not d % factor:
  190.                 print 'Дискриминант делится на %d, которое входит в m в первой степени. Число решений не меняется' % (factor, )
  191.             else:
  192.                 print 'Проверяем количество решений по модулю %d' % (factor**factors[factor], )
  193.                 fast_pow_mod(d, phi(factor - 1) / 2, factor)
  194.                 print 'Астрологи объявили %d квадратичным вычетом по модулю %d. Количество решений удваивается.' % (d, factor, )
  195.                 res *= 2
  196.     print 'Итого решений: %d' % (res, )
  197.     return res
  198.  
  199. def str_polynomial(coef, letter):
  200.     coef = coef[::-1]
  201.     letter = str(letter)
  202.     return ' + '.join(reversed(map(lambda deg: ('%d*%s^%d' % (coef[deg], letter, deg)), xrange(len(coef)))))
  203.  
  204. def polynomial_solves_number(coef, m):
  205.     def f(x):
  206.         res = 0
  207.         for c in coef:
  208.             res = res*x + c
  209.         return res
  210.     def f_p(x):
  211.         res = 0
  212.         _coef = coef[::-1]
  213.         return sum(map(lambda n: n * x**(n-1) * _coef[n], xrange(1, len(coef))))
  214.     print 'Ищем число решений %s = 0 (mod %d)' % (str_polynomial(coef, 'x'), m, )
  215.     factors = factorization(m)
  216.     solutions_diff_modules = {}
  217.     for factor in factors:
  218.         solutions = []
  219.         print 'Считаем число решений по модулю %d' % (factor**factors[factor], )
  220.         print 'Ищем решения по модулю %d (переборчик) и пытаемся их поднять' % (factor, )
  221.         print
  222.         for i in xrange(factor):
  223.             if f(i) % factor:
  224.                 print 'f(%d) = %d, не решение' % (i, f(i), )
  225.             else:
  226.                 print 'f(%d) = %d, решение' % (i, f(i), )
  227.                 c_f_p = f_p(i)
  228.                 print 'f\'(%d) = %d' % (i, c_f_p, )
  229.                 if c_f_p % factor != 0:
  230.                     print 'Это решение поднимается единственным образом'
  231.                     cur_sol = i
  232.                     for cur_deg in xrange(2, factors[factor]+1):
  233.                         for t in xrange(0, p):
  234.                             if (f(cur_sol)/(factor**cur_deg) + t*c_f_p) % factor == 0:
  235.                                 print 'f(%d) / %d^%d + f\'(%d)*%d = 0 (p), f(%d) = 0 (p^%d+1)' % (cur_sol, factor, cur_deg, cur_sol, t, cur_sol + t*factor**cur_deg, )
  236.                                 solutions += 1
  237.                 else:
  238.                     print 'Производная равна нулю... придется париться с подъемом:('
  239.                     cur_candidats = [i]
  240.                     cur_deg = 1
  241.                     while cur_deg < factors[factor]:
  242.                         print 'Пытаемся поднять решения со степени %d до %d' % (cur_deg, cur_deg + 1, )
  243.                         next_candidats = []
  244.                         for candidat in cur_candidats:
  245.                             print 'Пробуем поднять %d: f(%d) = %d' % (candidat, candidat, f(candidat), )
  246.                             if not f(candidat) % (factor ** (cur_deg + 1)):
  247.                                 print 'Подходит, значит, добавляем кучу решений'
  248.                                 for t in xrange(0, factor):
  249.                                     next_candidats.append(candidat + t * factor**cur_deg)
  250.                             else:
  251.                                 print 'Не подходит. Дальше не поднимаем.'
  252.                         cur_deg += 1
  253.                         cur_candidats = next_candidats
  254.                         print 'Решения mod %d^%d: %s', (factor, cur_deg, ', '.join(map(str, next_candidats)), )
  255.                 print
  256.         print
  257.  
  258. class RationalNumber:
  259.     def __reduce(self):
  260.         if self.nominator == 0:
  261.             return self
  262.         g = gcd(self.nominator, self.denominator, False)
  263.         if g < 0:
  264.             g *= -1
  265.         self.nominator /= g
  266.         self.denominator /= g
  267.         return self
  268.  
  269.     def __init__(self, nominator, denominator):
  270.         self.nominator = nominator
  271.         self.denominator = denominator
  272.         self.__reduce()
  273.  
  274.     def __neg__(self):
  275.         return self.__class__(-self.nominator, self.denominator)
  276.     def __pos__(self):
  277.         return self
  278.     def __abs__(self):
  279.         return self.__class__(abs(self.nominator), self.denominator)
  280.     def __float__(self):
  281.         return float(self.nominator) / self.denominator
  282.     def __str__(self):
  283.         return '(%d/%d)' % (self.nominator, self.denominator, )
  284.     def __add__(self, other):
  285.         return self.__class__(self.nominator * other.denominator + self.denominator * other.nominator, self.denominator * other.denominator).__reduce()
  286.     def __sub__(self, other):
  287.         return self.__class__(self.nominator * other.denominator - self.denominator * other.nominator, self.denominator * other.denominator).__reduce()
  288.     def __mul__(self, other):
  289.         return self.__class__(self.nominator * other.nominator, self.denominator * other.denominator).__reduce()
  290.     def __div__(self, other):
  291.         return self.__class__(self.nominator * other.denominator, self.denominator * other.nominator).__reduce()
  292.  
  293. def purely_periodic_continued_fraction(coefs):
  294.     print 'Раскрываем понемногу'
  295.     nomenator_free = 1
  296.     nomenator_x = coefs[-1]
  297.     denomenator_free = 0
  298.     denomenator_x = 1
  299.     for coef in coefs[-2::-1]:
  300.         print '(%d*x + %d)/(%d*x + %d)' % (nomenator_x, nomenator_free, denomenator_x, denomenator_free)
  301.         nomenator_x, nomenator_free, denomenator_x, denomenator_free = coef*nomenator_x+denomenator_x, coef*nomenator_free+denomenator_free, nomenator_x, nomenator_free
  302.         print '(%d*x + %d)/(%d*x + %d)' % (nomenator_x, nomenator_free, denomenator_x, denomenator_free)
  303.     a = denomenator_x
  304.     b = denomenator_free - nomenator_x
  305.     c = -nomenator_free
  306.     print '%d*x^2 + %d*x + %d = 0' % (a, b, c, )
  307.     d = b*b - 4*a*c
  308.     print 'd = %d' % (d, )
  309.     print 'x = (%d ± sqrt(%d))/%d' % (-b, d, 2*a)
  310.  
  311. def number_to_periodic_continued_fraction(normal_part, root, root_coef, denominator, prec = 0.001):
  312.     approx_root = max(filter(lambda n: n*n <= root, xrange(root+1)))
  313.     real_value = (float(normal_part) + root_coef * sqrt(root)) / denominator
  314.     print 'sqrt(%d) ≈ %d' % (root, approx_root, )
  315.     calculated = {}
  316.     a_coefs = []
  317.     i = 0
  318.     while (normal_part, root_coef, denominator) not in calculated:
  319.         #calculated.append((normal_part, root_coef, denominator))
  320.         a = int((normal_part + sqrt(root)*root_coef) / denominator)
  321.         a_coefs.append(a)
  322.         calculated[(normal_part, root_coef, denominator)] = i
  323.         print 'a_%d = %d' % (i, a, )
  324.         normal_part, root_coef, denominator = denominator*(normal_part - a*denominator), -root_coef*denominator, (normal_part - a*denominator)**2 - root_coef**2 * root
  325.         g = gcd(root_coef, gcd(normal_part, denominator))
  326.         normal_part /= g
  327.         root_coef /= g
  328.         denominator /= g
  329.         print 'α_%d = (%d + %d*sqrt(%d))/%d' % (i, normal_part, root_coef, root, denominator, )
  330.         i += 1
  331.     print 'Предпериод: %s' % (', '.join(map(str, a_coefs[:calculated[(normal_part, root_coef, denominator)]])), )
  332.     print 'Период: %s' % (', '.join(map(str, a_coefs[calculated[(normal_part, root_coef, denominator)]:])), )
  333.     all_as = a_coefs[:calculated[(normal_part, root_coef, denominator)]] + a_coefs[calculated[(normal_part, root_coef, denominator)]:] * 100
  334.     ps = {-2: 0, -1: 1}
  335.     qs = {-2: 1, -1: 0}
  336.     a = all_as
  337.     a_coefs = all_as
  338.     for i in xrange(0, 50):
  339.         ps[i] = a[i]*ps[i-1] + ps[i-2]
  340.         qs[i] = a[i]*qs[i-1] + qs[i-2]
  341.     real_values = map(lambda n: float(ps[n])/qs[n], xrange(30))
  342.     first_ok = min(filter(lambda n: abs(real_value - real_values[n]) <= prec, xrange(0, 30)))
  343.     print 'i\ta\tp\tq\tq_n(q_{n+1}+q_n)\tq_n*q_{n+1}'
  344.     for i in xrange(first_ok + 2):
  345.         print '%d\t%d\t%d\t%d\t%d\t\t\t%d' % (i, a[i], ps[i], qs[i], qs[i]*(qs[i+1]+qs[i]), qs[i]*qs[i+1])
  346.  
Advertisement
Add Comment
Please, Sign In to add comment