Skip to content

Commit 2a3a697

Browse files
authored
feat(blockchain): add all_diophantine_solutions with type hints & doctests (#12999)
* feat(blockchain): add all_diophantine_solutions with type hints & doctests * feat(blockchain): add all_diophantine_solutions; move above __main__, remove future import
1 parent a530636 commit 2a3a697

1 file changed

Lines changed: 58 additions & 0 deletions

File tree

‎blockchain/diophantine_equation.py‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,64 @@ def extended_gcd(a: int, b: int) -> tuple[int, int, int]:
100100
return (d, x, y)
101101

102102

103+
def all_diophantine_solutions(
104+
a: int,
105+
b: int,
106+
c: int,
107+
n: int = 2,
108+
) -> list[tuple[int, int]]:
109+
"""
110+
Return up to `n` integer solutions (x, y) to the linear Diophantine equation
111+
a*x + b*y = c using the extended Euclidean algorithm.
112+
113+
Raises
114+
------
115+
ValueError
116+
If no integer solutions exist.
117+
118+
Time complexity
119+
---------------
120+
O(log(max(|a|, |b|))) to compute a base solution using extended_gcd;
121+
plus O(n) to enumerate `n` solutions.
122+
123+
Space complexity
124+
----------------
125+
O(1) beyond the returned list.
126+
127+
Examples
128+
--------
129+
>>> all_diophantine_solutions(10, 6, 14, n=2)
130+
[(-7, 14), (-4, 9)]
131+
>>> all_diophantine_solutions(10, 6, 14, n=4)
132+
[(-7, 14), (-4, 9), (-1, 4), (2, -1)]
133+
>>> all_diophantine_solutions(3, 6, 10, n=1)
134+
Traceback (most recent call last):
135+
...
136+
ValueError: No integer solutions exist for a=3, b=6, c=10
137+
"""
138+
if a == 0 and b == 0:
139+
if c == 0:
140+
# Infinite solutions; return one canonical solution.
141+
return [(0, 0)][: min(1, n)]
142+
raise ValueError("No integer solutions exist for a=0, b=0, c!=0")
143+
144+
g, xg, yg = extended_gcd(abs(a), abs(b))
145+
if c % g != 0:
146+
msg = f"No integer solutions exist for a={a}, b={b}, c={c}"
147+
raise ValueError(msg)
148+
149+
# Scale a particular solution to ax + by = c
150+
x0, y0 = xg * (c // g), yg * (c // g)
151+
if a < 0:
152+
x0 = -x0
153+
if b < 0:
154+
y0 = -y0
155+
156+
# General solution: x = x0 + t*(b/g), y = y0 - t*(a/g)
157+
dx, dy = b // g, a // g
158+
return [(x0 + t * dx, y0 - t * dy) for t in range(n)]
159+
160+
103161
if __name__ == "__main__":
104162
from doctest import testmod
105163

0 commit comments

Comments
 (0)