From 4e994b33183d253002d7b5f025c14c01fcea43ef Mon Sep 17 00:00:00 2001 From: Aarya Yuvraj Balwadkar Date: Sun, 1 Oct 2023 14:42:50 +0530 Subject: [PATCH 1/2] Shifted CRT, modular division to linear_algebra directory --- blockchain/chinese_remainder_theorem.py | 95 --------------- blockchain/modular_division.py | 154 ------------------------ 2 files changed, 249 deletions(-) delete mode 100644 blockchain/chinese_remainder_theorem.py delete mode 100644 blockchain/modular_division.py diff --git a/blockchain/chinese_remainder_theorem.py b/blockchain/chinese_remainder_theorem.py deleted file mode 100644 index d3e75e77922a..000000000000 --- a/blockchain/chinese_remainder_theorem.py +++ /dev/null @@ -1,95 +0,0 @@ -""" -Chinese Remainder Theorem: -GCD ( Greatest Common Divisor ) or HCF ( Highest Common Factor ) - -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 -""" -from __future__ import annotations - - -# Extended Euclid -def extended_euclid(a: int, b: int) -> tuple[int, int]: - """ - >>> extended_euclid(10, 6) - (-1, 2) - - >>> extended_euclid(7, 5) - (-2, 3) - - """ - if b == 0: - return (1, 0) - (x, y) = extended_euclid(b, a % b) - k = a // b - return (y, x - k * y) - - -# Uses ExtendedEuclid to find inverses -def chinese_remainder_theorem(n1: int, r1: int, n2: int, r2: int) -> int: - """ - >>> 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 - - >>> chinese_remainder_theorem(6,1,4,3) - 14 - - """ - (x, y) = extended_euclid(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 invert_modulo(a: int, n: int) -> int: - """ - >>> invert_modulo(2, 5) - 3 - - >>> invert_modulo(8,7) - 1 - - """ - (b, x) = extended_euclid(a, n) - if b < 0: - b = (b % n + n) % n - return b - - -# Same a above using InvertingModulo -def chinese_remainder_theorem2(n1: int, r1: int, n2: int, r2: int) -> int: - """ - >>> chinese_remainder_theorem2(5,1,7,3) - 31 - - >>> chinese_remainder_theorem2(6,1,4,3) - 14 - - """ - 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__": - from doctest import testmod - - testmod(name="chinese_remainder_theorem", verbose=True) - testmod(name="chinese_remainder_theorem2", verbose=True) - testmod(name="invert_modulo", verbose=True) - testmod(name="extended_euclid", verbose=True) diff --git a/blockchain/modular_division.py b/blockchain/modular_division.py deleted file mode 100644 index a9d0f65c5b27..000000000000 --- a/blockchain/modular_division.py +++ /dev/null @@ -1,154 +0,0 @@ -from __future__ import annotations - - -def modular_division(a: int, b: int, n: int) -> int: - """ - Modular Division : - An efficient algorithm for dividing b by a modulo n. - - GCD ( Greatest Common Divisor ) or HCF ( Highest Common Factor ) - - Given three integers a, b, and n, such that gcd(a,n)=1 and n>1, the algorithm should - return an integer x such that 0≤x≤n−1, and b/a=x(modn) (that is, b=ax(modn)). - - Theorem: - a has a multiplicative inverse modulo n iff gcd(a,n) = 1 - - - This find x = b*a^(-1) mod n - Uses ExtendedEuclid to find the inverse of a - - >>> modular_division(4,8,5) - 2 - - >>> modular_division(3,8,5) - 1 - - >>> modular_division(4, 11, 5) - 4 - - """ - assert n > 1 and a > 0 and greatest_common_divisor(a, n) == 1 - (d, t, s) = extended_gcd(n, a) # Implemented below - x = (b * s) % n - return x - - -def invert_modulo(a: int, n: int) -> int: - """ - This function find the inverses of a i.e., a^(-1) - - >>> invert_modulo(2, 5) - 3 - - >>> invert_modulo(8,7) - 1 - - """ - (b, x) = extended_euclid(a, n) # Implemented below - if b < 0: - b = (b % n + n) % n - return b - - -# ------------------ Finding Modular division using invert_modulo ------------------- - - -def modular_division2(a: int, b: int, n: int) -> int: - """ - This function used the above inversion of a to find x = (b*a^(-1))mod n - - >>> modular_division2(4,8,5) - 2 - - >>> modular_division2(3,8,5) - 1 - - >>> modular_division2(4, 11, 5) - 4 - - """ - s = invert_modulo(a, n) - x = (b * s) % n - return x - - -def extended_gcd(a: int, b: int) -> tuple[int, int, int]: - """ - 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) - >>> extended_gcd(10, 6) - (2, -1, 2) - - >>> extended_gcd(7, 5) - (1, -2, 3) - - ** extended_gcd function is used when d = gcd(a,b) is required in output - - """ - 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) - - -def extended_euclid(a: int, b: int) -> tuple[int, int]: - """ - Extended Euclid - >>> extended_euclid(10, 6) - (-1, 2) - - >>> extended_euclid(7, 5) - (-2, 3) - - """ - if b == 0: - return (1, 0) - (x, y) = extended_euclid(b, a % b) - k = a // b - return (y, x - k * y) - - -def greatest_common_divisor(a: int, b: int) -> int: - """ - Euclid's Lemma : d divides a and b, if and only if d divides a-b and b - Euclid's Algorithm - - >>> greatest_common_divisor(7,5) - 1 - - Note : In number theory, two integers a and b are said to be relatively prime, - mutually prime, or co-prime if the only positive integer (factor) that divides - both of them is 1 i.e., gcd(a,b) = 1. - - >>> greatest_common_divisor(121, 11) - 11 - - """ - if a < b: - a, b = b, a - - while a % b != 0: - a, b = b, a % b - - return b - - -if __name__ == "__main__": - from doctest import testmod - - testmod(name="modular_division", verbose=True) - testmod(name="modular_division2", verbose=True) - testmod(name="invert_modulo", verbose=True) - testmod(name="extended_gcd", verbose=True) - testmod(name="extended_euclid", verbose=True) - testmod(name="greatest_common_divisor", verbose=True) From f5e6b39317e848d900ee375d08ac2229f65b8cba Mon Sep 17 00:00:00 2001 From: Aarya Yuvraj Balwadkar Date: Sun, 1 Oct 2023 14:48:13 +0530 Subject: [PATCH 2/2] Shifted CRT, modular division to linear_algebra directory --- linear_algebra/chinese_remainder_theorem.py | 95 ++++++++++++ linear_algebra/modular_division.py | 154 ++++++++++++++++++++ 2 files changed, 249 insertions(+) create mode 100644 linear_algebra/chinese_remainder_theorem.py create mode 100644 linear_algebra/modular_division.py diff --git a/linear_algebra/chinese_remainder_theorem.py b/linear_algebra/chinese_remainder_theorem.py new file mode 100644 index 000000000000..d3e75e77922a --- /dev/null +++ b/linear_algebra/chinese_remainder_theorem.py @@ -0,0 +1,95 @@ +""" +Chinese Remainder Theorem: +GCD ( Greatest Common Divisor ) or HCF ( Highest Common Factor ) + +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 +""" +from __future__ import annotations + + +# Extended Euclid +def extended_euclid(a: int, b: int) -> tuple[int, int]: + """ + >>> extended_euclid(10, 6) + (-1, 2) + + >>> extended_euclid(7, 5) + (-2, 3) + + """ + if b == 0: + return (1, 0) + (x, y) = extended_euclid(b, a % b) + k = a // b + return (y, x - k * y) + + +# Uses ExtendedEuclid to find inverses +def chinese_remainder_theorem(n1: int, r1: int, n2: int, r2: int) -> int: + """ + >>> 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 + + >>> chinese_remainder_theorem(6,1,4,3) + 14 + + """ + (x, y) = extended_euclid(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 invert_modulo(a: int, n: int) -> int: + """ + >>> invert_modulo(2, 5) + 3 + + >>> invert_modulo(8,7) + 1 + + """ + (b, x) = extended_euclid(a, n) + if b < 0: + b = (b % n + n) % n + return b + + +# Same a above using InvertingModulo +def chinese_remainder_theorem2(n1: int, r1: int, n2: int, r2: int) -> int: + """ + >>> chinese_remainder_theorem2(5,1,7,3) + 31 + + >>> chinese_remainder_theorem2(6,1,4,3) + 14 + + """ + 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__": + from doctest import testmod + + testmod(name="chinese_remainder_theorem", verbose=True) + testmod(name="chinese_remainder_theorem2", verbose=True) + testmod(name="invert_modulo", verbose=True) + testmod(name="extended_euclid", verbose=True) diff --git a/linear_algebra/modular_division.py b/linear_algebra/modular_division.py new file mode 100644 index 000000000000..a9d0f65c5b27 --- /dev/null +++ b/linear_algebra/modular_division.py @@ -0,0 +1,154 @@ +from __future__ import annotations + + +def modular_division(a: int, b: int, n: int) -> int: + """ + Modular Division : + An efficient algorithm for dividing b by a modulo n. + + GCD ( Greatest Common Divisor ) or HCF ( Highest Common Factor ) + + Given three integers a, b, and n, such that gcd(a,n)=1 and n>1, the algorithm should + return an integer x such that 0≤x≤n−1, and b/a=x(modn) (that is, b=ax(modn)). + + Theorem: + a has a multiplicative inverse modulo n iff gcd(a,n) = 1 + + + This find x = b*a^(-1) mod n + Uses ExtendedEuclid to find the inverse of a + + >>> modular_division(4,8,5) + 2 + + >>> modular_division(3,8,5) + 1 + + >>> modular_division(4, 11, 5) + 4 + + """ + assert n > 1 and a > 0 and greatest_common_divisor(a, n) == 1 + (d, t, s) = extended_gcd(n, a) # Implemented below + x = (b * s) % n + return x + + +def invert_modulo(a: int, n: int) -> int: + """ + This function find the inverses of a i.e., a^(-1) + + >>> invert_modulo(2, 5) + 3 + + >>> invert_modulo(8,7) + 1 + + """ + (b, x) = extended_euclid(a, n) # Implemented below + if b < 0: + b = (b % n + n) % n + return b + + +# ------------------ Finding Modular division using invert_modulo ------------------- + + +def modular_division2(a: int, b: int, n: int) -> int: + """ + This function used the above inversion of a to find x = (b*a^(-1))mod n + + >>> modular_division2(4,8,5) + 2 + + >>> modular_division2(3,8,5) + 1 + + >>> modular_division2(4, 11, 5) + 4 + + """ + s = invert_modulo(a, n) + x = (b * s) % n + return x + + +def extended_gcd(a: int, b: int) -> tuple[int, int, int]: + """ + 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) + >>> extended_gcd(10, 6) + (2, -1, 2) + + >>> extended_gcd(7, 5) + (1, -2, 3) + + ** extended_gcd function is used when d = gcd(a,b) is required in output + + """ + 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) + + +def extended_euclid(a: int, b: int) -> tuple[int, int]: + """ + Extended Euclid + >>> extended_euclid(10, 6) + (-1, 2) + + >>> extended_euclid(7, 5) + (-2, 3) + + """ + if b == 0: + return (1, 0) + (x, y) = extended_euclid(b, a % b) + k = a // b + return (y, x - k * y) + + +def greatest_common_divisor(a: int, b: int) -> int: + """ + Euclid's Lemma : d divides a and b, if and only if d divides a-b and b + Euclid's Algorithm + + >>> greatest_common_divisor(7,5) + 1 + + Note : In number theory, two integers a and b are said to be relatively prime, + mutually prime, or co-prime if the only positive integer (factor) that divides + both of them is 1 i.e., gcd(a,b) = 1. + + >>> greatest_common_divisor(121, 11) + 11 + + """ + if a < b: + a, b = b, a + + while a % b != 0: + a, b = b, a % b + + return b + + +if __name__ == "__main__": + from doctest import testmod + + testmod(name="modular_division", verbose=True) + testmod(name="modular_division2", verbose=True) + testmod(name="invert_modulo", verbose=True) + testmod(name="extended_gcd", verbose=True) + testmod(name="extended_euclid", verbose=True) + testmod(name="greatest_common_divisor", verbose=True)