Skip to content

Commit

Permalink
Simplify euclidean algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
jonas-lj committed May 5, 2023
1 parent d3f7418 commit 53924b2
Show file tree
Hide file tree
Showing 14 changed files with 46 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public E apply(Vector<E> a, Vector<E> m) {
return a.get(0);
}

EuclideanAlgorithm.Result<E> bezout = euclideanAlgorithm.gcd(m.get(0), m.get(1));
EuclideanAlgorithm.Result<E> bezout = euclideanAlgorithm.applyExtended(m.get(0), m.get(1));

Calculator<E> c = new Calculator<>(domain);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,35 @@ public EuclideanAlgorithm(EuclideanDomain<E> domain) {
this.ring = domain;
}

public E apply(E a, E b) {
if (ring.isZero(b)) {
return a;
}
return apply(b, ring.mod(a, b));
}

public E apply(List<E> inputs) {
if (inputs == null || inputs.isEmpty()) {
throw new IllegalArgumentException("Empty input list");
}

if (inputs.size() == 1) {
return inputs.get(0);
}
return apply(inputs.get(0), apply(inputs.subList(1, inputs.size())));
}

public E apply(E... inputs) {
return apply(List.of(inputs));
}

/**
* Calculate the greatest common divisor <i>d</i> of <i>a</i> and <i>b</i>, and the coefficients
* <i>x,y</i> of the Bezout identity <i>ax + by = d</i> .
*
* @return The triple <i>(d, x, y)</i>.
*/
public Result<E> gcd(E a, E b) {
public Result<E> applyExtended(E a, E b) {
E s_1 = ring.zero();
E s_0 = ring.identity();
E t_1 = ring.identity();
Expand All @@ -47,19 +69,19 @@ public Result<E> gcd(E a, E b) {
return new Result<>(r_0, s_0, t_0);
}

public ExtendedResult<E> gcd(List<E> inputs) {
public ExtendedResult<E> applyExtended(List<E> inputs) {
if (inputs.size() == 1) {
return new ExtendedResult<>(inputs.get(0), List.of(this.ring.identity()));
}
ExtendedResult<E> recursion = gcd(inputs.subList(1, inputs.size()));
Result<E> result = gcd(inputs.get(0), recursion.gcd);
ExtendedResult<E> recursion = applyExtended(inputs.subList(1, inputs.size()));
Result<E> result = applyExtended(inputs.get(0), recursion.gcd);
LinkedList<E> bezoutCoefficients = recursion.bezout.stream().map(bPrime -> ring.multiply(bPrime, result.y())).collect(Collectors.toCollection(LinkedList::new));
bezoutCoefficients.addFirst(result.x());
return new ExtendedResult<>(result.gcd, bezoutCoefficients);
}

public ExtendedResult<E> gcd(E... inputs) {
return gcd(List.of(inputs));
public ExtendedResult<E> applyExtended(E... inputs) {
return applyExtended(List.of(inputs));
}

public record Result<E>(E gcd, E x, E y) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ private Vector<E> sub(Vector<E> v, Vector<E> u) {
}

private E gcd(E a, E b) {
return euclideanAlgorithm.gcd(a, b).gcd();
return euclideanAlgorithm.applyExtended(a, b).gcd();
}

private Vector<E> normalize(Vector<E> v) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public FieldOfFractions(EuclideanDomain<E> ring) {
}

public Fraction<E> reduce(E n, E d) {
E gcd = euclideanAlgorithm.gcd(n, d).gcd();
E gcd = euclideanAlgorithm.applyExtended(n, d).gcd();
return new Fraction<>(baseRing.divide(n, gcd).getFirst(),
baseRing.divide(d, gcd).getFirst());
}
Expand Down
4 changes: 2 additions & 2 deletions common/src/test/java/AlgorithmsTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public void testEuclideanAlgorithm() {
for (int i = 0; i < tests; i++) {
BigInteger a = new BigInteger(16, random);
BigInteger b = new BigInteger(16, random);
EuclideanAlgorithm.Result<BigInteger> gcd = new EuclideanAlgorithm<>(integers).gcd(a, b);
EuclideanAlgorithm.Result<BigInteger> gcd = new EuclideanAlgorithm<>(integers).applyExtended(a, b);
Assert.assertEquals(a.gcd(b), gcd.gcd());
Assert.assertEquals(gcd.gcd(), gcd.x().multiply(a).add(gcd.y().multiply(b)));
}
Expand All @@ -136,7 +136,7 @@ public void testEuclideanAlgorithm() {
BigInteger a = new BigInteger(16, random);
BigInteger b = new BigInteger(16, random);
BigInteger c = new BigInteger(16, random);
EuclideanAlgorithm.ExtendedResult<BigInteger> gcd = new EuclideanAlgorithm<>(integers).gcd(a, b, c);
EuclideanAlgorithm.ExtendedResult<BigInteger> gcd = new EuclideanAlgorithm<>(integers).applyExtended(a, b, c);
Assert.assertEquals(a.gcd(b).gcd(c), gcd.gcd());
Assert.assertEquals(gcd.gcd(), gcd.bezout().get(0).multiply(a).add(gcd.bezout().get(1).multiply(b)).add(gcd.bezout().get(2).multiply(c)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public AlgebraicFieldExtension(F field, String element, Polynomial<E> minimalPol
@Override
public Polynomial<E> invert(Polynomial<E> a) {
EuclideanAlgorithm.Result<Polynomial<E>> r =
new EuclideanAlgorithm<>((PolynomialRing<E>) super.ring).gcd(a, super.mod);
new EuclideanAlgorithm<>((PolynomialRing<E>) super.ring).applyExtended(a, super.mod);
assert (r.gcd().degree() == 0);
return r.x().scale(field.invert(r.gcd().getCoefficient(0)), field);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public BigFiniteField(BigPrimeField baseField, Polynomial<BigInteger> mod) {
@Override
public Polynomial<BigInteger> invert(Polynomial<BigInteger> a) {
return new EuclideanAlgorithm<>((PolynomialRing<BigInteger>) super.ring)
.gcd(a, mod).x();
.applyExtended(a, mod).x();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public BigPrimeField(BigInteger p) {
@Override
public BigInteger invert(BigInteger a) {
EuclideanAlgorithm.Result<BigInteger> xgcd =
new EuclideanAlgorithm<>(BigIntegers.getInstance()).gcd(a, super.getModulus());
new EuclideanAlgorithm<>(BigIntegers.getInstance()).applyExtended(a, super.getModulus());
if (!xgcd.gcd().equals(BigInteger.ONE)) {
throw new NotInvertibleException(a);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public Polynomial<Integer> element(Integer... coefficients) {
@Override
public Polynomial<Integer> invert(Polynomial<Integer> a) {
return new EuclideanAlgorithm<>((PolynomialRing<Integer>) super.ring)
.gcd(a, mod).x();
.applyExtended(a, mod).x();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public PrimeField(Integer p) {
@Override
public Integer invert(Integer a) {
EuclideanAlgorithm.Result<Integer> gcd = new EuclideanAlgorithm<>(Integers.getInstance())
.gcd(a, super.mod);
.applyExtended(a, super.mod);
if (gcd.gcd() != 1) {
throw new NotInvertibleException(super.mod);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public Integer apply(Polynomial<Integer> f) {
𝔽ₚx.subtract(gₖ, 𝔽ₚx.identity()));

for (Polynomial<Integer> candidate : candidates) {
Polynomial<Integer> g = gcd.gcd(fₖ, candidate).gcd();
Polynomial<Integer> g = gcd.applyExtended(fₖ, candidate).gcd();
if (g.degree() > 0) {
return 𝔽ₚ.subtract(apply(g), k);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import java.math.BigInteger;

/**
* This implements the ideal class group for a negative discrimant.
* This implements the ideal class group for a negative discriminant.
*/
public class ClassGroup implements Group<QuadraticForm<BigInteger, BigIntegers>> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,7 @@ public QuadraticForm<E, R> compose(QuadraticForm<E, R> other) {

E a1 = this.a;
E a2 = other.a;
E b1 = this.b;
E b2 = other.b;
E c1 = this.c;
E c2 = other.c;

if (ordering.compare(a1, a2) > 0) {
Expand All @@ -126,17 +124,17 @@ public QuadraticForm<E, R> compose(QuadraticForm<E, R> other) {
throw new IllegalArgumentException("Discriminants must be equal.");
}

EuclideanAlgorithm<E> euclideanAlgorithm = new EuclideanAlgorithm<>(ring);
EuclideanAlgorithm<E> gcd = new EuclideanAlgorithm<>(ring);

E s = ring.divideExact(ring.add(b1, b2), 2);
E s = ring.divideExact(ring.add(this.b, b2), 2);
E n = ring.subtract(b2, s);

E d, y1;
if (ring.divides(a2, a1)) {
d = a1;
y1 = ring.zero();
} else {
EuclideanAlgorithm.Result<E> duv = euclideanAlgorithm.gcd(a1, a2);
EuclideanAlgorithm.Result<E> duv = gcd.applyExtended(a1, a2);
d = duv.gcd();
y1 = duv.y();
}
Expand All @@ -147,13 +145,13 @@ public QuadraticForm<E, R> compose(QuadraticForm<E, R> other) {
y2 = ring.negate(ring.identity());
d1 = d;
} else {
EuclideanAlgorithm.Result<E> duv = euclideanAlgorithm.gcd(s, d);
EuclideanAlgorithm.Result<E> duv = gcd.applyExtended(s, d);
d1 = duv.gcd();
x2 = duv.x();
y2 = ring.negate(duv.y());
}

E g = euclideanAlgorithm.gcd(d1, c1, c2, ring.abs(n, ordering)).gcd();
E g = gcd.applyExtended(d1, this.c, c2, ring.abs(n, ordering)).gcd();
E v1 = ring.divideExact(ring.multiply(g, a1), d1);
E v2 = ring.divideExact(a2, d1);
E r = ring.subtract(ring.multiply(y1, y2, n), ring.mod(ring.multiply(x2, c2), v1));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public BigInteger solve(List<BigInteger> p, List<BigInteger> q) {
List<BigInteger> inputs = new ArrayList<>();
inputs.add(m);
inputs.addAll(p);
EuclideanAlgorithm.ExtendedResult<BigInteger> xgcd = euclideanAlgorithm.gcd(inputs);
EuclideanAlgorithm.ExtendedResult<BigInteger> xgcd = euclideanAlgorithm.applyExtended(inputs);
if (!xgcd.gcd().equals(BigInteger.ONE)) {
throw new IllegalArgumentException("m and p_1, ..., p_r are not pairwise co-prime.");
}
Expand Down

0 comments on commit 53924b2

Please sign in to comment.