From 2b7a31e69e5529e24e44d42147ebd525bb0d0666 Mon Sep 17 00:00:00 2001 From: OddExtension5 Date: Tue, 1 Oct 2019 21:26:51 +0530 Subject: [PATCH 1/4] added chinese_remainder_theorem --- .../chinese_remainder_theorem.py | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 data_structures/hashing/number_theory/chinese_remainder_theorem.py diff --git a/data_structures/hashing/number_theory/chinese_remainder_theorem.py b/data_structures/hashing/number_theory/chinese_remainder_theorem.py new file mode 100644 index 000000000000..a61ed16e41b2 --- /dev/null +++ b/data_structures/hashing/number_theory/chinese_remainder_theorem.py @@ -0,0 +1,44 @@ +# Chinese Remainder Theorem: + +# If GCD(a,b) = 1, then for any remainder ra modulo a and any remainder rb modulo b there exists integer n, +# such that n = ra (mod a) and n = ra(mod b). If n1 and n2 are two such integers, then n1=n2(mod ab) + +# Algorithm : + +# 1. Use extended euclid algorithm to find x,y such that a*x + b*y = 1 +# 2. Take n = ra*by + rb*ax + + +# Extended Euclid +def ExtendedEuclid(a, b): + if b == 0: + return (1, 0) + (x, y) = ExtendedEuclid(b, a % b) + k = a // b + return (y, x - k * y) + + +# Uses ExtendedEuclid to find inverses +def ChineseRemainderTheorem(n1, r1, n2, r2): + (x, y) = ExtendedEuclid(n1, n2) + m = n1 * n2 + n = r2 * x * n1 + r1 * y * n2 + return ((n % m + m) % m) + + +# ----------SAME SOLUTION USING InvertModulo instead ExtendedEuclid---------------- + +# This function find the inverses of a i.e., a^(-1) +def InvertModulo(a, n): + (b, x) = ExtendedEuclid(a, n) + if b < 0: + b = (b % n + n) % n + return b + + +# Same a above using InvertingModulo +def ChineseRemainderTheorem2(n1, r1, n2, r2): + x, y = InvertModulo(n1, n2), InvertModulo(n2, n1) + m = n1 * n2 + n = r2 * x * n1 + r1 * y * n2 + return (n % m + m) % m From 41a9414dec38b622f12fb572957accc6265a0212 Mon Sep 17 00:00:00 2001 From: OddExtension5 Date: Tue, 1 Oct 2019 22:09:59 +0530 Subject: [PATCH 2/4] Added Diophantine_equation algorithm --- .../number_theory/diophantine_equation.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 data_structures/hashing/number_theory/diophantine_equation.py diff --git a/data_structures/hashing/number_theory/diophantine_equation.py b/data_structures/hashing/number_theory/diophantine_equation.py new file mode 100644 index 000000000000..47040ee6a932 --- /dev/null +++ b/data_structures/hashing/number_theory/diophantine_equation.py @@ -0,0 +1,64 @@ +# Diophantine Equation : Given integers a,b,c ( at least one of a and b != 0), the diophantine equation +# a*x + b*y = c has a solution (where x and y are integers) iff gcd(a,b) divides c. + + +def diophantine(a, b, c): + assert c % gcd(a, b) == 0 # gcd(a,b) function implemented below + + (d, x, y) = extended_gcd(a, b) # extended_gcd(a,b) function implemented below + r = c / d + return (r * x, r * y) + + +# Lemma : if n|ab and gcd(a,n) = 1, then n|b. + +# Finding All solutions of Diophantine Equations: + +# Theorem : Let gcd(a,b) = d, a = d*p, b = d*q. If (x0,y0) is a solution of Diophantine Equation a*x + b*y = c. +# a*x0 + b*y0 = c, then all the solutions have the form a(x0 + t*q) + b(y0 - t*p) = c, where t is an arbitrary integer. + +# n is the number of solution you want, n = 2 by default + +def diophantine_all_soln(a, b, c, n=2): + (x0, y0) = diophantine(a, b, c) + d = gcd(a, b) + p = a // d + q = b // d + + for i in range(n): + x = x0 + i * q + y = y0 - i * p + print(x, y) + + +# Euclid's Lemma : d divides a and b, if and only if d divides a-b and b + +# Euclid's Algorithm + +def gcd(a, b): + if a < b: + a, b = b, a + + while a % b != 0: + a, b = b, a % b + + return b + + +# Extended Euclid's Algorithm : If d divides a and b and d = a*x + b*y for integers x and y, then d = gcd(a,b) + + +def extended_gcd(a, b): + assert a >= 0 and b >= 0 + + if b == 0: + d, x, y = a, 1, 0 + else: + (d, p, q) = extended_gcd(b, a % b) + x = q + y = p - q * (a // b) + + assert a % d == 0 and b % d == 0 + assert d == a * x + b * y + + return (d, x, y) From 72e9db49a52525227290698a4200d29dfd7f52b7 Mon Sep 17 00:00:00 2001 From: OddExtension5 Date: Wed, 2 Oct 2019 00:07:22 +0530 Subject: [PATCH 3/4] Update Diophantine eqn & chinese remainder theorem --- .../chinese_remainder_theorem.py | 26 +++++++++++++ .../number_theory/diophantine_equation.py | 38 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/data_structures/hashing/number_theory/chinese_remainder_theorem.py b/data_structures/hashing/number_theory/chinese_remainder_theorem.py index a61ed16e41b2..ed519d56b68e 100644 --- a/data_structures/hashing/number_theory/chinese_remainder_theorem.py +++ b/data_structures/hashing/number_theory/chinese_remainder_theorem.py @@ -8,6 +8,9 @@ # 1. Use extended euclid algorithm to find x,y such that a*x + b*y = 1 # 2. Take n = ra*by + rb*ax +# import testmod for testing our function +from doctest import testmod + # Extended Euclid def ExtendedEuclid(a, b): @@ -20,6 +23,17 @@ def ExtendedEuclid(a, b): # Uses ExtendedEuclid to find inverses def ChineseRemainderTheorem(n1, r1, n2, r2): + """ + >>> ChineseRemainderTheorem(5,1,7,3) + 31 + + Explanation : 31 is the smallest number such that + (i) When we divide it by 5, we get remainder 1 + (ii) When we divide it by 7, we get remainder 3 + + >>> ChineseRemainderTheorem(6,1,4,3) + 14 + """ (x, y) = ExtendedEuclid(n1, n2) m = n1 * n2 n = r2 * x * n1 + r1 * y * n2 @@ -38,7 +52,19 @@ def InvertModulo(a, n): # Same a above using InvertingModulo def ChineseRemainderTheorem2(n1, r1, n2, r2): + """ + >>> ChineseRemainderTheorem2(5,1,7,3) + 31 + + >>> ChineseRemainderTheorem2(6,1,4,3) + 14 + """ x, y = InvertModulo(n1, n2), InvertModulo(n2, n1) m = n1 * n2 n = r2 * x * n1 + r1 * y * n2 return (n % m + m) % m + + +if __name__ == '__main__': + testmod(name='ChineseRemainderTheorem', verbose=True) + testmod(name='ChineseRemainderTheorem2', verbose=True) diff --git a/data_structures/hashing/number_theory/diophantine_equation.py b/data_structures/hashing/number_theory/diophantine_equation.py index 47040ee6a932..435bb0438fdb 100644 --- a/data_structures/hashing/number_theory/diophantine_equation.py +++ b/data_structures/hashing/number_theory/diophantine_equation.py @@ -1,8 +1,23 @@ # Diophantine Equation : Given integers a,b,c ( at least one of a and b != 0), the diophantine equation # a*x + b*y = c has a solution (where x and y are integers) iff gcd(a,b) divides c. +# import testmod for testing our function +from doctest import testmod + def diophantine(a, b, c): + """ + >>> diophantine(10,6,14) + (-7.0, 14.0) + + >>> diophantine(391,299,-69) + (9.0, -12.0) + + But above equation has one more solution i.e., x = -4, y = 5. + That's why we need diophantine all solution function. + + """ + assert c % gcd(a, b) == 0 # gcd(a,b) function implemented below (d, x, y) = extended_gcd(a, b) # extended_gcd(a,b) function implemented below @@ -20,6 +35,24 @@ def diophantine(a, b, c): # n is the number of solution you want, n = 2 by default def diophantine_all_soln(a, b, c, n=2): + """ + >>> diophantine_all_soln(10, 6, 14) + -7.0 14.0 + -4.0 9.0 + + >>> diophantine_all_soln(10, 6, 14, 4) + -7.0 14.0 + -4.0 9.0 + -1.0 4.0 + 2.0 -1.0 + + >>> diophantine_all_soln(391, 299, -69, n = 4) + 9.0 -12.0 + 22.0 -29.0 + 35.0 -46.0 + 48.0 -63.0 + + """ (x0, y0) = diophantine(a, b, c) d = gcd(a, b) p = a // d @@ -62,3 +95,8 @@ def extended_gcd(a, b): assert d == a * x + b * y return (d, x, y) + + +if __name__ == '__main__': + testmod(name='diophantine', verbose=True) + testmod(name='diophantine_all_soln', verbose=True) From 33de1b1af0b8ded4032e1fb166fffb9427085fe7 Mon Sep 17 00:00:00 2001 From: OddExtension5 Date: Wed, 2 Oct 2019 11:08:12 +0530 Subject: [PATCH 4/4] Update Diophantine eqn & chinese remainder theorem --- .../chinese_remainder_theorem.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/data_structures/hashing/number_theory/chinese_remainder_theorem.py b/data_structures/hashing/number_theory/chinese_remainder_theorem.py index ed519d56b68e..c552241c139b 100644 --- a/data_structures/hashing/number_theory/chinese_remainder_theorem.py +++ b/data_structures/hashing/number_theory/chinese_remainder_theorem.py @@ -13,28 +13,28 @@ # Extended Euclid -def ExtendedEuclid(a, b): +def extended_euclid(a, b): if b == 0: return (1, 0) - (x, y) = ExtendedEuclid(b, a % b) + (x, y) = extended_euclid(b, a % b) k = a // b return (y, x - k * y) # Uses ExtendedEuclid to find inverses -def ChineseRemainderTheorem(n1, r1, n2, r2): +def chinese_remainder_theorem(n1, r1, n2, r2): """ - >>> ChineseRemainderTheorem(5,1,7,3) + >>> chinese_remainder_theorem(5,1,7,3) 31 Explanation : 31 is the smallest number such that (i) When we divide it by 5, we get remainder 1 (ii) When we divide it by 7, we get remainder 3 - >>> ChineseRemainderTheorem(6,1,4,3) + >>> chinese_remainder_theorem(6,1,4,3) 14 """ - (x, y) = ExtendedEuclid(n1, n2) + (x, y) = extended_euclid(n1, n2) m = n1 * n2 n = r2 * x * n1 + r1 * y * n2 return ((n % m + m) % m) @@ -43,28 +43,28 @@ def ChineseRemainderTheorem(n1, r1, n2, r2): # ----------SAME SOLUTION USING InvertModulo instead ExtendedEuclid---------------- # This function find the inverses of a i.e., a^(-1) -def InvertModulo(a, n): - (b, x) = ExtendedEuclid(a, n) +def invert_modulo(a, n): + (b, x) = extended_euclid(a, n) if b < 0: b = (b % n + n) % n return b # Same a above using InvertingModulo -def ChineseRemainderTheorem2(n1, r1, n2, r2): +def chinese_remainder_theorem2(n1, r1, n2, r2): """ - >>> ChineseRemainderTheorem2(5,1,7,3) + >>> chinese_remainder_theorem2(5,1,7,3) 31 - >>> ChineseRemainderTheorem2(6,1,4,3) + >>> chinese_remainder_theorem2(6,1,4,3) 14 """ - x, y = InvertModulo(n1, n2), InvertModulo(n2, n1) + x, y = invert_modulo(n1, n2), invert_modulo(n2, n1) m = n1 * n2 n = r2 * x * n1 + r1 * y * n2 return (n % m + m) % m if __name__ == '__main__': - testmod(name='ChineseRemainderTheorem', verbose=True) - testmod(name='ChineseRemainderTheorem2', verbose=True) + testmod(name='chinese_remainder_theorem', verbose=True) + testmod(name='chinese_remainder_theorem2', verbose=True)