22
33import java .util .Objects ;
44
5+ /**
6+ * A solver for linear Diophantine equations of the form ax + by = c.
7+ * <p>
8+ * A linear Diophantine equation is an equation in which only integer solutions
9+ * are allowed.
10+ * This solver uses the Extended Euclidean Algorithm to find integer solutions
11+ * (x, y)
12+ * for equations of the form ax + by = c, where a, b, and c are integers.
13+ * </p>
14+ * <p>
15+ * The equation has solutions if and only if gcd(a, b) divides c.
16+ * If solutions exist, this solver finds one particular solution.
17+ * </p>
18+ *
19+ * @see <a href="https://en.wikipedia.org/wiki/Diophantine_equation">Diophantine
20+ * Equation</a>
21+ * @see <a href=
22+ * "https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm">Extended
23+ * Euclidean Algorithm</a>
24+ */
525public final class LinearDiophantineEquationsSolver {
626 private LinearDiophantineEquationsSolver () {
727 }
828
29+ /**
30+ * Demonstrates the solver with a sample equation: 3x + 4y = 7.
31+ *
32+ * @param args command line arguments (not used)
33+ */
934 public static void main (String [] args ) {
1035 // 3x + 4y = 7
1136 final var toSolve = new Equation (3 , 4 , 7 );
1237 System .out .println (findAnySolution (toSolve ));
1338 }
1439
40+ /**
41+ * Finds any integer solution to the linear Diophantine equation ax + by = c.
42+ * <p>
43+ * The method returns one of three types of solutions:
44+ * <ul>
45+ * <li>A specific solution (x, y) if solutions exist</li>
46+ * <li>{@link Solution#NO_SOLUTION} if no integer solutions exist</li>
47+ * <li>{@link Solution#INFINITE_SOLUTIONS} if the equation is 0x + 0y = 0</li>
48+ * </ul>
49+ * </p>
50+ *
51+ * @param equation the linear Diophantine equation to solve
52+ * @return a Solution object containing the result
53+ * @throws NullPointerException if equation is null
54+ */
1555 public static Solution findAnySolution (final Equation equation ) {
1656 if (equation .a () == 0 && equation .b () == 0 && equation .c () == 0 ) {
1757 return Solution .INFINITE_SOLUTIONS ;
1858 }
59+ if (equation .a () == 0 && equation .b () == 0 ) {
60+ return Solution .NO_SOLUTION ;
61+ }
62+ if (equation .a () == 0 ) {
63+ if (equation .c () % equation .b () == 0 ) {
64+ return new Solution (0 , equation .c () / equation .b ());
65+ } else {
66+ return Solution .NO_SOLUTION ;
67+ }
68+ }
69+ if (equation .b () == 0 ) {
70+ if (equation .c () % equation .a () == 0 ) {
71+ return new Solution (equation .c () / equation .a (), 0 );
72+ } else {
73+ return Solution .NO_SOLUTION ;
74+ }
75+ }
1976 final var stub = new GcdSolutionWrapper (0 , new Solution (0 , 0 ));
2077 final var gcdSolution = gcd (equation .a (), equation .b (), stub );
2178 if (equation .c () % gcdSolution .getGcd () != 0 ) {
@@ -29,43 +86,100 @@ public static Solution findAnySolution(final Equation equation) {
2986 return toReturn ;
3087 }
3188
89+ /**
90+ * Computes the GCD of two integers using the Extended Euclidean Algorithm.
91+ * <p>
92+ * This method also finds coefficients x and y such that ax + by = gcd(a, b).
93+ * The coefficients are stored in the 'previous' wrapper object.
94+ * </p>
95+ *
96+ * @param a the first integer
97+ * @param b the second integer
98+ * @param previous a wrapper to store the solution coefficients
99+ * @return a GcdSolutionWrapper containing the GCD and coefficients
100+ */
32101 private static GcdSolutionWrapper gcd (final int a , final int b , final GcdSolutionWrapper previous ) {
33102 if (b == 0 ) {
34103 return new GcdSolutionWrapper (a , new Solution (1 , 0 ));
35104 }
36105 // stub wrapper becomes the `previous` of the next recursive call
37106 final var stubWrapper = new GcdSolutionWrapper (0 , new Solution (0 , 0 ));
38- final var next = /* recursive call */ gcd (b , a % b , stubWrapper );
107+ final var next = gcd (b , a % b , stubWrapper );
39108 previous .getSolution ().setX (next .getSolution ().getY ());
40109 previous .getSolution ().setY (next .getSolution ().getX () - (a / b ) * (next .getSolution ().getY ()));
41110 previous .setGcd (next .getGcd ());
42111 return new GcdSolutionWrapper (next .getGcd (), previous .getSolution ());
43112 }
44113
114+ /**
115+ * Represents a solution (x, y) to a linear Diophantine equation.
116+ * <p>
117+ * Special instances:
118+ * <ul>
119+ * <li>{@link #NO_SOLUTION} - indicates no integer solutions exist</li>
120+ * <li>{@link #INFINITE_SOLUTIONS} - indicates infinitely many solutions
121+ * exist</li>
122+ * </ul>
123+ * </p>
124+ */
45125 public static final class Solution {
46126
127+ /**
128+ * Singleton instance representing the case where no solution exists.
129+ */
47130 public static final Solution NO_SOLUTION = new Solution (Integer .MAX_VALUE , Integer .MAX_VALUE );
131+
132+ /**
133+ * Singleton instance representing the case where infinite solutions exist.
134+ */
48135 public static final Solution INFINITE_SOLUTIONS = new Solution (Integer .MIN_VALUE , Integer .MIN_VALUE );
136+
49137 private int x ;
50138 private int y ;
51139
140+ /**
141+ * Constructs a solution with the given x and y values.
142+ *
143+ * @param x the x coordinate of the solution
144+ * @param y the y coordinate of the solution
145+ */
52146 public Solution (int x , int y ) {
53147 this .x = x ;
54148 this .y = y ;
55149 }
56150
151+ /**
152+ * Gets the x value of this solution.
153+ *
154+ * @return the x value
155+ */
57156 public int getX () {
58157 return x ;
59158 }
60159
160+ /**
161+ * Gets the y value of this solution.
162+ *
163+ * @return the y value
164+ */
61165 public int getY () {
62166 return y ;
63167 }
64168
169+ /**
170+ * Sets the x value of this solution.
171+ *
172+ * @param x the new x value
173+ */
65174 public void setX (int x ) {
66175 this .x = x ;
67176 }
68177
178+ /**
179+ * Sets the y value of this solution.
180+ *
181+ * @param y the new y value
182+ */
69183 public void setY (int y ) {
70184 this .y = y ;
71185 }
@@ -95,14 +209,35 @@ public String toString() {
95209 }
96210 }
97211
212+ /**
213+ * Represents a linear Diophantine equation of the form ax + by = c.
214+ *
215+ * @param a the coefficient of x
216+ * @param b the coefficient of y
217+ * @param c the constant term
218+ */
98219 public record Equation (int a , int b , int c ) {
99220 }
100221
222+ /**
223+ * A wrapper class that holds both the GCD and the solution coefficients
224+ * from the Extended Euclidean Algorithm.
225+ * <p>
226+ * This class is used internally to pass results between recursive calls
227+ * of the GCD computation.
228+ * </p>
229+ */
101230 public static final class GcdSolutionWrapper {
102231
103232 private int gcd ;
104233 private Solution solution ;
105234
235+ /**
236+ * Constructs a GcdSolutionWrapper with the given GCD and solution.
237+ *
238+ * @param gcd the greatest common divisor
239+ * @param solution the solution coefficients
240+ */
106241 public GcdSolutionWrapper (int gcd , Solution solution ) {
107242 this .gcd = gcd ;
108243 this .solution = solution ;
@@ -120,18 +255,38 @@ public boolean equals(Object obj) {
120255 return (this .gcd == that .gcd && Objects .equals (this .solution , that .solution ));
121256 }
122257
258+ /**
259+ * Gets the GCD value.
260+ *
261+ * @return the GCD
262+ */
123263 public int getGcd () {
124264 return gcd ;
125265 }
126266
267+ /**
268+ * Sets the GCD value.
269+ *
270+ * @param gcd the new GCD value
271+ */
127272 public void setGcd (int gcd ) {
128273 this .gcd = gcd ;
129274 }
130275
276+ /**
277+ * Gets the solution coefficients.
278+ *
279+ * @return the solution
280+ */
131281 public Solution getSolution () {
132282 return solution ;
133283 }
134284
285+ /**
286+ * Sets the solution coefficients.
287+ *
288+ * @param solution the new solution
289+ */
135290 public void setSolution (Solution solution ) {
136291 this .solution = solution ;
137292 }
0 commit comments