Skip to content

Commit

Permalink
Improve/refactor gaussian integer methods
Browse files Browse the repository at this point in the history
  • Loading branch information
axkr committed Dec 3, 2023
1 parent 429e811 commit 70f45fc
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 143 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1818,12 +1818,12 @@ public IExpr eComIntArg(final IComplex c0, final IInteger i1) {
@Override
public IExpr e2ComArg(final IComplex c0, final IComplex c1) {
// TODO implement GCD for gaussian integers
IInteger[] gi0 = c0.gaussianIntegers();
IInteger[] gi1 = c1.gaussianIntegers();
Optional<IInteger[]> gi0 = c0.gaussianIntegers();
Optional<IInteger[]> gi1 = c1.gaussianIntegers();

if (gi0 != null && gi1 != null) {
if (gi0.isPresent() && gi1.isPresent()) {
// ComplexSym devidend = ComplexSym.valueOf(c0.getRealPart(), c0.getImaginaryPart());
IInteger[] result = GaussianInteger.gcd(gi0, gi1);
IInteger[] result = GaussianInteger.gcd(gi0.get(), gi1.get());
if (result != null) {
return F.complex(result[0], result[1]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2698,15 +2698,15 @@ public IExpr evaluate(final IAST ast, EvalEngine engine) {
BigInteger re = BigInteger.ONE;
if (arg1.isInteger()) {
re = ((IInteger) arg1).toBigNumerator();
return GaussianInteger.factorize(re, BigInteger.ZERO, arg1);
return GaussianInteger.factorize((IInteger) arg1, re, BigInteger.ZERO);
} else if (arg1.isComplex()) {
IComplex c = (IComplex) arg1;
IRational rer = c.getRealPart();
IRational imr = c.getImaginaryPart();
if (rer.isInteger() && imr.isInteger()) {
re = ((IInteger) rer).toBigNumerator();
BigInteger im = ((IInteger) imr).toBigNumerator();
return GaussianInteger.factorize(re, im, arg1);
IRational real = c.getRealPart();
IRational imaginary = c.getImaginaryPart();
if (real.isInteger() && imaginary.isInteger()) {
re = ((IInteger) real).toBigNumerator();
BigInteger im = ((IInteger) imaginary).toBigNumerator();
return GaussianInteger.factorize((IComplex) arg1, re, im);
}
}
}
Expand Down Expand Up @@ -5202,24 +5202,10 @@ public IExpr evaluate(final IAST ast, EvalEngine engine) {
if (re.isInteger()) {
IRational im = ((IComplex) arg1).im();
if (im.isInteger()) {
IAST factors = GaussianInteger.factorize(((IInteger) re).toBigNumerator(),
((IInteger) im).toBigNumerator(), arg1);
if (factors.isListOfLists()) {
for (int i = 1; i < factors.size(); i++) {
IAST subList = factors.getAST(i);
if (!subList.isList2()) {
return S.False;
}
if (subList.second().isInteger()) {
IInteger exponent = (IInteger) subList.second();
if (exponent.isGE(F.C2)) {
return S.False;
}
}
}
return S.True;
}
return F.booleSymbol(
GaussianInteger.isSquareFree((IComplex) arg1, (IInteger) re, (IInteger) im));
}

}
}
return S.False;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.matheclipse.core.builtin;

import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Predicate;
import org.hipparchus.linear.FieldMatrix;
Expand Down Expand Up @@ -480,17 +481,18 @@ public boolean evalArg1Boole(final IExpr arg1, EvalEngine engine, OptionArgs opt
if (!option.isTrue()) {
return evalArg1Boole(arg1, engine);
}
IInteger[] reImParts = arg1.gaussianIntegers();
if (reImParts == null) {
Optional<IInteger[]> reImParts = arg1.gaussianIntegers();
if (reImParts.isEmpty()) {
return false;
}
if (reImParts[1].isZero()) {
return reImParts[0].isEven();
IInteger[] gaussian = reImParts.get();
if (gaussian[1].isZero()) {
return gaussian[0].isEven();
}
if (reImParts[0].isZero()) {
return reImParts[1].isEven();
if (gaussian[0].isZero()) {
return gaussian[1].isEven();
}
return reImParts[0].isEven() && reImParts[1].isEven();
return gaussian[0].isEven() && gaussian[1].isEven();
}

@Override
Expand Down Expand Up @@ -951,20 +953,21 @@ public boolean evalArg1Boole(final IExpr arg1, EvalEngine engine, OptionArgs opt
if (!option.isTrue()) {
return evalArg1Boole(arg1, engine);
}
IInteger[] reImParts = arg1.gaussianIntegers();
if (reImParts == null) {
Optional<IInteger[]> reImParts = arg1.gaussianIntegers();
if (reImParts.isEmpty()) {
return false;
}
if (reImParts[1].isZero()) {
return reImParts[0].isOdd();
IInteger[] gaussian = reImParts.get();
if (gaussian[1].isZero()) {
return gaussian[0].isOdd();
}
if (reImParts[0].isZero()) {
return reImParts[1].isOdd();
if (gaussian[0].isZero()) {
return gaussian[1].isOdd();
}
if (reImParts[0].isOdd() && reImParts[1].isOdd()) {
if (gaussian[0].isOdd() && gaussian[1].isOdd()) {
return false;
}
return reImParts[0].isOdd() || reImParts[1].isOdd();
return gaussian[0].isOdd() || gaussian[1].isOdd();
}

@Override
Expand Down Expand Up @@ -1241,24 +1244,25 @@ public boolean evalArg1Boole(final IExpr arg1, EvalEngine engine, OptionArgs opt
if (!option.isTrue()) {
return evalArg1Boole(arg1, engine);
}
IInteger[] reImParts = arg1.gaussianIntegers();
if (reImParts == null) {
Optional<IInteger[]> reImParts = arg1.gaussianIntegers();
if (reImParts.isEmpty()) {
return false;
}
if (reImParts[1].isZero()) {
if (reImParts[0].isProbablePrime()) {
return reImParts[0].abs().mod(F.C4).equals(F.C3);
IInteger[] gaussian = reImParts.get();
if (gaussian[1].isZero()) {
if (gaussian[0].isProbablePrime()) {
return gaussian[0].abs().mod(F.C4).equals(F.C3);
}
return false;
}
if (reImParts[0].isZero()) {
if (reImParts[1].isProbablePrime()) {
return reImParts[1].abs().mod(F.C4).equals(F.C3);
if (gaussian[0].isZero()) {
if (gaussian[1].isProbablePrime()) {
return gaussian[1].abs().mod(F.C4).equals(F.C3);
}
return false;
}
// re^2 + im^2 is probable prime?
return reImParts[0].powerRational(2L).add(reImParts[1].powerRational(2L)).isProbablePrime();
return gaussian[0].powerRational(2L).add(gaussian[1].powerRational(2L)).isProbablePrime();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
import java.util.Stack;
Expand Down Expand Up @@ -695,8 +696,8 @@ public IInteger factorial() {

/** {@inheritDoc} */
@Override
public IInteger[] gaussianIntegers() {
return new IInteger[] {this, F.C0};
public Optional<IInteger[]> gaussianIntegers() {
return Optional.of(new IInteger[] {this, F.C0});
}

/** {@inheritDoc} */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static org.matheclipse.core.expression.F.Times;
import static org.matheclipse.core.expression.S.Pi;
import java.math.BigInteger;
import java.util.Optional;
import java.util.function.Function;
import org.apfloat.Apcomplex;
import org.apfloat.Apfloat;
Expand Down Expand Up @@ -408,11 +409,11 @@ public String fullFormString() {

/** {@inheritDoc} */
@Override
public IInteger[] gaussianIntegers() {
public Optional<IInteger[]> gaussianIntegers() {
if (fReal.isInteger() && fImaginary.isInteger()) {
return new IInteger[] {((IInteger) fReal), ((IInteger) fImaginary)};
return Optional.of(new IInteger[] {((IInteger) fReal), ((IInteger) fImaginary)});
}
return null;
return Optional.empty();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
Expand Down Expand Up @@ -1078,8 +1079,8 @@ default String fullFormString() {
*
* @return <code>null</code> if this is not a Gaussian integer
*/
default IInteger[] gaussianIntegers() {
return null;
default Optional<IInteger[]> gaussianIntegers() {
return Optional.empty();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IASTAppendable;
import org.matheclipse.core.interfaces.IBigNumber;
import org.matheclipse.core.interfaces.IComplex;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IInteger;

Expand All @@ -29,10 +31,20 @@ public final class GaussianInteger {
private BigInteger ValA, ValB;
private int Ind;

public static IAST factorize(BigInteger re, BigInteger im, IExpr num) {
/**
* Factor a gaussian integer number.
*
* @param gaussianInteger gaussian integer represented by an {@link IBigNumber} instance (i.e.
* instance of {@link IComplex} or {@link IInteger})
* @param realPart the real part of the gaussian integer
* @param imaginaryPart the imaginary part of the gaussian integer
* @return
*/
public static IAST factorize(IBigNumber gaussianInteger, BigInteger realPart,
BigInteger imaginaryPart) {
GaussianInteger g = new GaussianInteger();
SortedMap<ComplexSym, Integer> complexMap = new TreeMap<ComplexSym, Integer>();
g.gaussianFactorization2(re, im, complexMap);
g.gaussianFactorization2(realPart, imaginaryPart, complexMap);
IASTAppendable list = F.ListAlloc(complexMap.size() + 1);
IExpr factor = F.C1;
IASTAppendable ast = F.TimesAlloc(complexMap.size());
Expand All @@ -46,7 +58,7 @@ public static IAST factorize(BigInteger re, BigInteger im, IExpr num) {
ast.append(F.Power(key, is));
}
}
factor = F.eval(F.Divide(num, ast));
factor = F.eval(F.Divide(gaussianInteger, ast));
if (!factor.isOne()) {
list.append(F.list(factor, F.C1));
}
Expand All @@ -58,6 +70,38 @@ public static IAST factorize(BigInteger re, BigInteger im, IExpr num) {
return list;
}

/**
* Test if the gaussian integer is square free.
*
* @param gaussianInteger gaussian integer represented by an {@link IBigNumber} instance (i.e.
* instance of {@link IComplex} or {@link IInteger})
* @param realPart the real part of the gaussian integer
* @param imaginaryPart the imaginary part of the gaussian integer
*
* @return
*/
public static boolean isSquareFree(IBigNumber gaussianInteger, IInteger realPart,
IInteger imaginaryPart) {
IAST factors =
factorize(gaussianInteger, realPart.toBigNumerator(), imaginaryPart.toBigNumerator());
if (factors.isListOfLists()) {
for (int i = 1; i < factors.size(); i++) {
IAST subList = factors.getAST(i);
if (!subList.isList2()) {
return false;
}
if (subList.second().isInteger()) {
IInteger exponent = (IInteger) subList.second();
if (exponent.isGE(F.C2)) {
return false;
}
}
}
return true;
}
return false;
}

void gaussianFactorization2(BigInteger re, BigInteger im,
SortedMap<ComplexSym, Integer> complexMap) {
BigInteger BigInt2;
Expand Down Expand Up @@ -218,7 +262,7 @@ public static IInteger[] quotientRemainder(final IInteger[] c1, final IInteger[]
}

/**
* Greatest common divisor of the gaussian <code>IInteger</code> numbers <code>g1, g2</code>.
* Greatest common divisor of the gaussian {@link IInteger} numbers <code>g1, g2</code>.
*
* @param g1
* @param g2
Expand Down
Loading

0 comments on commit 70f45fc

Please sign in to comment.