Linear Diophantine Equations Solver

package com.thealgorithms.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 + ']';
        }

    }
}
Algerlogo

Β© Alger 2022

About us

We are a group of programmers helping each other build new things, whether it be writing complex encryption programs, or simple ciphers. Our goal is to work together to document and model beautiful, helpful and interesting algorithms using code. We are an open-source community - anyone can contribute. We check each other's work, communicate and collaborate to solve problems. We strive to be welcoming, respectful, yet make sure that our code follows the latest programming guidelines.