|
16 | 16 | import java.math.BigInteger;
|
17 | 17 | import java.util.ArrayList;
|
18 | 18 | import java.util.HashMap;
|
| 19 | +import java.util.Iterator; |
19 | 20 | import java.util.List;
|
20 | 21 | import java.util.Map;
|
21 | 22 | import java.util.SortedMap;
|
|
79 | 80 | import org.matheclipse.core.interfaces.ISymbol;
|
80 | 81 | import org.matheclipse.core.numbertheory.GaussianInteger;
|
81 | 82 | import org.matheclipse.core.numbertheory.Primality;
|
| 83 | +import org.matheclipse.core.polynomials.QuarticSolver; |
82 | 84 | import org.matheclipse.core.sympy.series.Sequences;
|
83 | 85 | import org.matheclipse.core.visit.VisitorExpr;
|
84 | 86 | import com.google.common.math.BigIntegerMath;
|
|
88 | 90 | import edu.jas.arith.ModInteger;
|
89 | 91 | import edu.jas.arith.ModIntegerRing;
|
90 | 92 | import edu.jas.poly.GenPolynomial;
|
| 93 | +import edu.jas.poly.Monomial; |
91 | 94 | import edu.jas.ufd.FactorAbstract;
|
92 | 95 | import edu.jas.ufd.FactorFactory;
|
| 96 | +import io.github.mangara.diophantine.QuadraticSolver; |
| 97 | +import io.github.mangara.diophantine.Utils; |
| 98 | +import io.github.mangara.diophantine.XYPair; |
| 99 | +import io.github.mangara.diophantine.quadratic.ParabolicSolver; |
| 100 | +import io.github.mangara.diophantine.quadratic.PellsSolver; |
93 | 101 |
|
94 | 102 | public final class NumberTheory {
|
95 | 103 |
|
@@ -6616,4 +6624,123 @@ private static IAST quadraticIrrationalPlus(IAST plusAST, IASTMutable resultList
|
6616 | 6624 | }
|
6617 | 6625 | return F.NIL;
|
6618 | 6626 | }
|
| 6627 | + |
| 6628 | + public static IAST diophantinePolynomial(final IExpr expr, IAST varList, |
| 6629 | + int maximumNumberOfResults) { |
| 6630 | + VariablesSet varSet = new VariablesSet(varList); |
| 6631 | + IASTMutable result = F.NIL; |
| 6632 | + try { |
| 6633 | + // try to generate a common expression polynomial |
| 6634 | + JASConvert<edu.jas.arith.BigInteger> jas = new JASConvert<edu.jas.arith.BigInteger>( |
| 6635 | + varSet.getArrayList(), edu.jas.arith.BigInteger.ZERO); |
| 6636 | + GenPolynomial<edu.jas.arith.BigInteger> ePoly = jas.expr2JAS(expr, false); |
| 6637 | + result = diophantinePolynomial(ePoly, varList, maximumNumberOfResults); |
| 6638 | + result = QuarticSolver.sortASTArguments(result); |
| 6639 | + return result; |
| 6640 | + } catch (JASConversionException e2) { |
| 6641 | + e2.printStackTrace(); |
| 6642 | + } |
| 6643 | + return result; |
| 6644 | + } |
| 6645 | + |
| 6646 | + private static IASTAppendable diophantinePolynomial( |
| 6647 | + GenPolynomial<edu.jas.arith.BigInteger> polynomial, IAST varList, |
| 6648 | + int maximumNumberOfResults) { |
| 6649 | + long varDegree = polynomial.degree(0); |
| 6650 | + |
| 6651 | + if (polynomial.isConstant()) { |
| 6652 | + return F.ListAlloc(1); |
| 6653 | + } |
| 6654 | + // a*x^2 + b*x*y + c*y^2 + d*x + e*y + f = 0 |
| 6655 | + BigInteger a = BigInteger.ZERO; |
| 6656 | + BigInteger b = BigInteger.ZERO; |
| 6657 | + BigInteger c = BigInteger.ZERO; |
| 6658 | + BigInteger d = BigInteger.ZERO; |
| 6659 | + BigInteger e = BigInteger.ZERO; |
| 6660 | + BigInteger f = BigInteger.ZERO; |
| 6661 | + try { |
| 6662 | + if (varDegree <= 2) { |
| 6663 | + if (varList.argSize() == 1) { |
| 6664 | + // x is only variable => b=0;c=0;e=0; |
| 6665 | + for (Monomial<edu.jas.arith.BigInteger> monomial : polynomial) { |
| 6666 | + edu.jas.arith.BigInteger coeff = monomial.coefficient(); |
| 6667 | + BigInteger zz = coeff.val; |
| 6668 | + long xExp = monomial.exponent().getVal(0); |
| 6669 | + if (xExp == 2) { |
| 6670 | + a = zz; |
| 6671 | + } else if (xExp == 1) { |
| 6672 | + d = zz; |
| 6673 | + } else if (xExp == 2) { |
| 6674 | + f = zz; |
| 6675 | + } else { |
| 6676 | + throw new ArithmeticException( |
| 6677 | + "diophantinePolynomial::Unexpected exponent value: " + xExp); |
| 6678 | + } |
| 6679 | + } |
| 6680 | + } else if (varList.argSize() == 2) { |
| 6681 | + // x and y are both variables |
| 6682 | + // a*x^2 + b*x*y + c*y^2 + d*x + e*y + f = 0 |
| 6683 | + for (Monomial<edu.jas.arith.BigInteger> monomial : polynomial) { |
| 6684 | + edu.jas.arith.BigInteger coeff = monomial.coefficient(); |
| 6685 | + BigInteger zz = coeff.val; |
| 6686 | + int xi = monomial.exponent().varIndex(0); |
| 6687 | + int yi = monomial.exponent().varIndex(1); |
| 6688 | + long xExp = monomial.exponent().getVal(xi); |
| 6689 | + long yExp = monomial.exponent().getVal(yi); |
| 6690 | + if (xExp == 2 && yExp == 0) { |
| 6691 | + a = zz; |
| 6692 | + } else if (xExp == 1 && yExp == 1) { |
| 6693 | + b = zz; |
| 6694 | + } else if (xExp == 0 && yExp == 2) { |
| 6695 | + c = zz; |
| 6696 | + } else if (xExp == 1 && yExp == 0) { |
| 6697 | + d = zz; |
| 6698 | + } else if (xExp == 0 && yExp == 1) { |
| 6699 | + e = zz; |
| 6700 | + } else if (xExp == 0 && yExp == 0) { |
| 6701 | + f = zz; |
| 6702 | + } else { |
| 6703 | + throw new ArithmeticException( |
| 6704 | + "diophantinePolynomial::Unexpected exponent value: " + xExp); |
| 6705 | + } |
| 6706 | + } |
| 6707 | + } |
| 6708 | + Iterator<XYPair> diophantineSolver = null; |
| 6709 | + IASTAppendable result = F.ListAlloc(); |
| 6710 | + if (maximumNumberOfResults == 1 && c.signum() < 0 && f.equals(BigInteger.valueOf(-4)) |
| 6711 | + && b.signum() == 0 && d.signum() == 0 && e.signum() == 0) { |
| 6712 | + BigInteger cNegate = c.negate(); |
| 6713 | + if (!Utils.isSquare(cNegate)) { |
| 6714 | + // use Pell's equation if -c is not a perfect square |
| 6715 | + XYPair xyPair = PellsSolver.leastPositivePellsFourSolution(cNegate); |
| 6716 | + result.append(F.List(F.Rule(varList.arg1(), F.ZZ(xyPair.x)), |
| 6717 | + F.Rule(varList.arg2(), F.ZZ(xyPair.y)))); |
| 6718 | + return result; |
| 6719 | + } |
| 6720 | + } |
| 6721 | + if (a.signum() != 0 || b.signum() != 0 || c.signum() != 0) { |
| 6722 | + // D := b^2 - 4ac && D == 0 |
| 6723 | + BigInteger D = b.multiply(b).subtract(a.multiply(c).multiply(BigInteger.valueOf(4))); |
| 6724 | + if (D.signum() == 0) { |
| 6725 | + diophantineSolver = ParabolicSolver.solve(a, b, c, d, e, f); |
| 6726 | + } |
| 6727 | + } |
| 6728 | + if (diophantineSolver == null) { |
| 6729 | + diophantineSolver = QuadraticSolver.solve(a, b, c, d, e, f); |
| 6730 | + } |
| 6731 | + |
| 6732 | + int n = 0; |
| 6733 | + while (diophantineSolver.hasNext() && n++ < maximumNumberOfResults) { |
| 6734 | + XYPair xyPair = diophantineSolver.next(); |
| 6735 | + result.append(F.List(F.Rule(varList.arg1(), F.ZZ(xyPair.x)), |
| 6736 | + F.Rule(varList.arg2(), F.ZZ(xyPair.y)))); |
| 6737 | + } |
| 6738 | + return result; |
| 6739 | + } |
| 6740 | + } catch (ArithmeticException aex) { |
| 6741 | + // |
| 6742 | + } |
| 6743 | + |
| 6744 | + return F.NIL; |
| 6745 | + } |
6619 | 6746 | }
|
0 commit comments