Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions Maths/LinearDiophantineEquationsSolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package Maths;

import java.util.Objects;

public final class LinearDiophantineEquationsSolver {

public static void main(String[] args) {
// 3x + 4y = 7
final var toSolve = new Equation(3, 4, 7);
System.out.println(findAnySolution(toSolve));
}

public static Solution findAnySolution(final Equation equation) {
if (equation.a() == 0 && equation.b() == 0 && equation.c() == 0) {
return Solution.INFINITE_SOLUTIONS;
}
final var stub = new GcdSolutionWrapper(0, new Solution(0, 0));
final var gcdSolution = gcd(equation.a(), equation.b(), stub);
if (equation.c() % gcdSolution.getGcd() != 0) {
return Solution.NO_SOLUTION;
}
final var toReturn = new Solution(0, 0);
var xToSet = stub.getSolution().getX() * (equation.c() / stub.getGcd());
var yToSet = stub.getSolution().getY() * (equation.c() / stub.getGcd());
toReturn.setX(xToSet);
toReturn.setY(yToSet);
return toReturn;
}

private static GcdSolutionWrapper gcd(final int a, final int b, final GcdSolutionWrapper previous) {
if (b == 0) {
return new GcdSolutionWrapper(a, new Solution(1, 0));
}
// stub wrapper becomes the `previous` of the next recursive call
final var stubWrapper = new GcdSolutionWrapper(0, new Solution(0, 0));
final var next = /* recursive call */ gcd(b, a % b, stubWrapper);
previous.getSolution().setX(next.getSolution().getY());
previous.getSolution().setY(next.getSolution().getX() - (a / b) * (next.getSolution().getY()));
previous.setGcd(next.getGcd());
return new GcdSolutionWrapper(next.getGcd(), previous.getSolution());
}

public static final class Solution {
public static final Solution NO_SOLUTION = new Solution(Integer.MAX_VALUE, Integer.MAX_VALUE);
public static final Solution INFINITE_SOLUTIONS = new Solution(Integer.MIN_VALUE, Integer.MIN_VALUE);
private int x;
private int y;

public Solution(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() {
return x;
}

public int getY() {
return y;
}

public void setX(int x) {
this.x = x;
}

public void setY(int y) {
this.y = y;
}

@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (Solution) obj;
return this.x == that.x &&
this.y == that.y;
}

@Override
public int hashCode() {
return Objects.hash(x, y);
}

@Override
public String toString() {
return "Solution[" +
"x=" + x + ", " +
"y=" + y + ']';
}

}

public record Equation(int a, int b, int c) {
}

public static final class GcdSolutionWrapper {
private int gcd;
private Solution solution;

public GcdSolutionWrapper(int gcd, Solution solution) {
this.gcd = gcd;
this.solution = solution;
}

@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (GcdSolutionWrapper) obj;
return this.gcd == that.gcd &&
Objects.equals(this.solution, that.solution);
}

public int getGcd() {
return gcd;
}

public void setGcd(int gcd) {
this.gcd = gcd;
}

public Solution getSolution() {
return solution;
}

public void setSolution(Solution solution) {
this.solution = solution;
}

@Override
public int hashCode() {
return Objects.hash(gcd, solution);
}

@Override
public String toString() {
return "GcdSolutionWrapper[" +
"gcd=" + gcd + ", " +
"solution=" + solution + ']';
}

}
}