Skip to content

Removed redundant greatest_common_divisor code #9358

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Oct 9, 2023
Merged
32 changes: 4 additions & 28 deletions blockchain/diophantine_equation.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from __future__ import annotations

from maths.greatest_common_divisor import greatest_common_divisor


def diophantine(a: int, b: int, c: int) -> tuple[float, float]:
"""
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.
iff greatest_common_divisor(a,b) divides c.
GCD ( Greatest Common Divisor ) or HCF ( Highest Common Factor )
Expand All @@ -22,7 +24,7 @@ def diophantine(a: int, b: int, c: int) -> tuple[float, float]:

assert (
c % greatest_common_divisor(a, b) == 0
) # greatest_common_divisor(a,b) function implemented below
) # greatest_common_divisor(a,b) is in maths directory
(d, x, y) = extended_gcd(a, b) # extended_gcd(a,b) function implemented below
r = c / d
return (r * x, r * y)
Expand Down Expand Up @@ -69,32 +71,6 @@ def diophantine_all_soln(a: int, b: int, c: int, n: int = 2) -> None:
print(x, 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


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
Expand Down
27 changes: 2 additions & 25 deletions blockchain/modular_division.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

from maths.greatest_common_divisor import greatest_common_divisor


def modular_division(a: int, b: int, n: int) -> int:
"""
Expand Down Expand Up @@ -118,31 +120,6 @@ def extended_euclid(a: int, b: int) -> tuple[int, int]:
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

Expand Down
6 changes: 4 additions & 2 deletions ciphers/affine_cipher.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import random
import sys

from maths.greatest_common_divisor import gcd_by_iterative

from . import cryptomath_module as cryptomath

SYMBOLS = (
Expand All @@ -26,7 +28,7 @@ def check_keys(key_a: int, key_b: int, mode: str) -> None:
"Key A must be greater than 0 and key B must "
f"be between 0 and {len(SYMBOLS) - 1}."
)
if cryptomath.gcd(key_a, len(SYMBOLS)) != 1:
if gcd_by_iterative(key_a, len(SYMBOLS)) != 1:
sys.exit(
f"Key A {key_a} and the symbol set size {len(SYMBOLS)} "
"are not relatively prime. Choose a different key."
Expand Down Expand Up @@ -76,7 +78,7 @@ def get_random_key() -> int:
while True:
key_b = random.randint(2, len(SYMBOLS))
key_b = random.randint(2, len(SYMBOLS))
if cryptomath.gcd(key_b, len(SYMBOLS)) == 1 and key_b % len(SYMBOLS) != 0:
if gcd_by_iterative(key_b, len(SYMBOLS)) == 1 and key_b % len(SYMBOLS) != 0:
return key_b * len(SYMBOLS) + key_b


Expand Down
7 changes: 2 additions & 5 deletions ciphers/cryptomath_module.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
def gcd(a: int, b: int) -> int:
while a != 0:
a, b = b % a, a
return b
from maths.greatest_common_divisor import gcd_by_iterative


def find_mod_inverse(a: int, m: int) -> int:
if gcd(a, m) != 1:
if gcd_by_iterative(a, m) != 1:
msg = f"mod inverse of {a!r} and {m!r} does not exist"
raise ValueError(msg)
u1, u2, u3 = 1, 0, a
Expand Down
14 changes: 1 addition & 13 deletions ciphers/hill_cipher.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,7 @@

import numpy


def greatest_common_divisor(a: int, b: int) -> int:
"""
>>> greatest_common_divisor(4, 8)
4
>>> greatest_common_divisor(8, 4)
4
>>> greatest_common_divisor(4, 7)
1
>>> greatest_common_divisor(0, 10)
10
"""
return b if a == 0 else greatest_common_divisor(b % a, a)
from maths.greatest_common_divisor import greatest_common_divisor


class HillCipher:
Expand Down
4 changes: 3 additions & 1 deletion ciphers/rsa_key_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import random
import sys

from maths.greatest_common_divisor import gcd_by_iterative

from . import cryptomath_module, rabin_miller


Expand All @@ -27,7 +29,7 @@ def generate_key(key_size: int) -> tuple[tuple[int, int], tuple[int, int]]:
# Generate e that is relatively prime to (p - 1) * (q - 1)
while True:
e = random.randrange(2 ** (key_size - 1), 2 ** (key_size))
if cryptomath_module.gcd(e, (p - 1) * (q - 1)) == 1:
if gcd_by_iterative(e, (p - 1) * (q - 1)) == 1:
break

# Calculate d that is mod inverse of e
Expand Down
13 changes: 3 additions & 10 deletions maths/carmichael_number.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,12 @@

power(b, n-1) MOD n = 1,
for all b ranging from 1 to n such that b and
n are relatively prime, i.e, gcd(b, n) = 1
n are relatively prime, i.e, greatest_common_divisor(b, n) = 1

Examples of Carmichael Numbers: 561, 1105, ...
https://en.wikipedia.org/wiki/Carmichael_number
"""


def gcd(a: int, b: int) -> int:
if a < b:
return gcd(b, a)
if a % b == 0:
return b
return gcd(b, a % b)
from maths.greatest_common_divisor import greatest_common_divisor


def power(x: int, y: int, mod: int) -> int:
Expand All @@ -33,7 +26,7 @@ def power(x: int, y: int, mod: int) -> int:
def is_carmichael_number(n: int) -> bool:
b = 2
while b < n:
if gcd(b, n) == 1 and power(b, n - 1, n) != 1:
if greatest_common_divisor(b, n) == 1 and power(b, n - 1, n) != 1:
return False
b += 1
return True
Expand Down
22 changes: 2 additions & 20 deletions maths/least_common_multiple.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import unittest
from timeit import timeit

from maths.greatest_common_divisor import greatest_common_divisor


def least_common_multiple_slow(first_num: int, second_num: int) -> int:
"""
Expand All @@ -20,26 +22,6 @@ def least_common_multiple_slow(first_num: int, second_num: int) -> int:
return common_mult


def greatest_common_divisor(a: int, b: int) -> int:
"""
Calculate Greatest Common Divisor (GCD).
see greatest_common_divisor.py
>>> greatest_common_divisor(24, 40)
8
>>> greatest_common_divisor(1, 1)
1
>>> greatest_common_divisor(1, 800)
1
>>> greatest_common_divisor(11, 37)
1
>>> greatest_common_divisor(3, 5)
1
>>> greatest_common_divisor(16, 4)
4
"""
return b if a == 0 else greatest_common_divisor(b % a, a)


def least_common_multiple_fast(first_num: int, second_num: int) -> int:
"""
Find the least common multiple of two numbers.
Expand Down
40 changes: 4 additions & 36 deletions maths/primelib.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
is_even(number)
is_odd(number)
gcd(number1, number2) // greatest common divisor
kg_v(number1, number2) // least common multiple
get_divisors(number) // all divisors of 'number' inclusive 1, number
is_perfect_number(number)
Expand All @@ -40,6 +39,8 @@

from math import sqrt

from maths.greatest_common_divisor import gcd_by_iterative


def is_prime(number: int) -> bool:
"""
Expand Down Expand Up @@ -317,39 +318,6 @@ def goldbach(number):
# ----------------------------------------------


def gcd(number1, number2):
"""
Greatest common divisor
input: two positive integer 'number1' and 'number2'
returns the greatest common divisor of 'number1' and 'number2'
"""

# precondition
assert (
isinstance(number1, int)
and isinstance(number2, int)
and (number1 >= 0)
and (number2 >= 0)
), "'number1' and 'number2' must been positive integer."

rest = 0

while number2 != 0:
rest = number1 % number2
number1 = number2
number2 = rest

# precondition
assert isinstance(number1, int) and (
number1 >= 0
), "'number' must been from type int and positive"

return number1


# ----------------------------------------------------


def kg_v(number1, number2):
"""
Least common multiple
Expand Down Expand Up @@ -567,14 +535,14 @@ def simplify_fraction(numerator, denominator):
), "The arguments must been from type int and 'denominator' != 0"

# build the greatest common divisor of numerator and denominator.
gcd_of_fraction = gcd(abs(numerator), abs(denominator))
gcd_of_fraction = gcd_by_iterative(abs(numerator), abs(denominator))

# precondition
assert (
isinstance(gcd_of_fraction, int)
and (numerator % gcd_of_fraction == 0)
and (denominator % gcd_of_fraction == 0)
), "Error in function gcd(...,...)"
), "Error in function gcd_by_iterative(...,...)"

return (numerator // gcd_of_fraction, denominator // gcd_of_fraction)

Expand Down
19 changes: 2 additions & 17 deletions project_euler/problem_005/sol2.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from maths.greatest_common_divisor import greatest_common_divisor

"""
Project Euler Problem 5: https://projecteuler.net/problem=5
Expand All @@ -16,23 +18,6 @@
"""


def greatest_common_divisor(x: int, y: int) -> int:
"""
Euclidean Greatest Common Divisor algorithm
>>> greatest_common_divisor(0, 0)
0
>>> greatest_common_divisor(23, 42)
1
>>> greatest_common_divisor(15, 33)
3
>>> greatest_common_divisor(12345, 67890)
15
"""

return x if y == 0 else greatest_common_divisor(y, x % y)


def lcm(x: int, y: int) -> int:
"""
Least Common Multiple.
Expand Down