diff --git a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/LinearAlgebra.java b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/LinearAlgebra.java index f26c5922e8..9cf4c80580 100644 --- a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/LinearAlgebra.java +++ b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/LinearAlgebra.java @@ -28,6 +28,8 @@ import static org.matheclipse.core.expression.F.Subtract; import static org.matheclipse.core.expression.F.Times; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; import java.util.List; import java.util.function.Predicate; import org.apache.logging.log4j.LogManager; @@ -72,6 +74,7 @@ import org.matheclipse.core.eval.util.IndexTableGenerator; import org.matheclipse.core.expression.ASTRealMatrix; import org.matheclipse.core.expression.ASTRealVector; +import org.matheclipse.core.expression.ComplexNum; import org.matheclipse.core.expression.F; import org.matheclipse.core.expression.ImplementationStatus; import org.matheclipse.core.expression.S; @@ -2055,17 +2058,19 @@ public IExpr evaluate(final IAST ast, EvalEngine engine) { } else { boolean hasNumericArgument = arg1.isNumericArgument(true);// (IAST.CONTAINS_NUMERIC_ARG); if (!hasNumericArgument) { - ISymbol x = F.Dummy("x"); - IExpr m = engine.evaluate(F.CharacteristicPolynomial(arg1, x)); - if (m.isPolynomial(x)) { - IExpr eigenValues = - RootsFunctions.roots(m, false, F.List(x), false, true, engine); - if (eigenValues.isList()) { - if (eigenValues.forAll(v -> v.isNumericFunction())) { - IAST sortFunction = - sortValuesIfNumeric((IASTMutable) eigenValues, numberOfEigenvalues); - if (sortFunction.isPresent()) { - return engine.evaluate(sortFunction); + if (dim[0] <= 4 && dim[1] <= 4) { + ISymbol x = F.Dummy("x"); + IExpr m = engine.evaluate(F.CharacteristicPolynomial(arg1, x)); + if (m.isPolynomial(x)) { + IExpr eigenValues = + RootsFunctions.roots(m, false, F.List(x), false, true, engine); + if (eigenValues.isList()) { + if (eigenValues.forAll(v -> v.isNumericFunction())) { + IAST sortFunction = + sortValuesIfNumeric((IASTMutable) eigenValues, numberOfEigenvalues); + if (sortFunction.isPresent()) { + return engine.evaluate(sortFunction); + } } } } @@ -2081,7 +2086,7 @@ public IExpr evaluate(final IAST ast, EvalEngine engine) { // switch to numeric calculation IExpr eigenValues = numericEval(ast, engine); if (eigenValues.isList()) { - IAST sortFunction = sortValuesIfNumeric((IASTMutable) eigenValues, numberOfEigenvalues); + IAST sortFunction = pickValues((IASTMutable) eigenValues, numberOfEigenvalues); if (sortFunction.isPresent()) { return engine.evaluate(sortFunction); } @@ -2119,11 +2124,41 @@ private IAST sortValuesIfNumeric(IAST eigenValuesList, final IExpr numberOfEigen return eigenValuesList; } + private static IAST pickValues(IAST eigenValuesList, final IExpr numberOfEigenvalues) { + if (eigenValuesList.forAll(v -> v.isNumericFunction())) { + if (numberOfEigenvalues != null && numberOfEigenvalues.isPresent()) { + int n = numberOfEigenvalues.toIntDefault(); + if (n < 0) { + if (n == Integer.MIN_VALUE) { + return F.NIL; + } + return eigenValuesList.copyFrom(eigenValuesList.size() + n, eigenValuesList.size()); + } + return eigenValuesList.copyFrom(1, n + 1); + } + return eigenValuesList; + } + return eigenValuesList; + } + @Override public IExpr matrixEval(FieldMatrix matrix, Predicate zeroChecker) { return F.NIL; } + static final class AbsReverseComparator implements Comparator { + + @Override + public final int compare(final Complex o1, final Complex o2) { + double n1 = o2.norm(); + double n2 = o1.norm(); + if (F.isFuzzyEquals(n1, n2, Config.DEFAULT_CHOP_DELTA)) { + return ComplexNum.compare(o1, o2); + } + return n1 < n2 ? -1 : 1; + } + } + @Override public IAST realMatrixEval(RealMatrix matrix, EvalEngine engine) { // TODO https://github.com/Hipparchus-Math/hipparchus/issues/174 @@ -2133,6 +2168,7 @@ public IAST realMatrixEval(RealMatrix matrix, EvalEngine engine) { ComplexEigenDecomposition.DEFAULT_EPSILON_AV_VD_CHECK, // (c1, c2) -> Double.compare(c2.norm(), c1.norm())); Complex[] eigenvalues = ced.getEigenvalues(); + Arrays.sort(eigenvalues, 0, eigenvalues.length, new AbsReverseComparator()); return F.mapRange(0, eigenvalues.length, (int i) -> { if (F.isZero(eigenvalues[i].getImaginary())) { return F.num(eigenvalues[i].getReal()); diff --git a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/expression/ComplexNum.java b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/expression/ComplexNum.java index f6aa41c914..3760f66010 100644 --- a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/expression/ComplexNum.java +++ b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/expression/ComplexNum.java @@ -338,15 +338,15 @@ public int compareAbsValueToOne() { return Double.compare(temp, 1.0); } - public int compareTo(final Complex that) { - if (fComplex.getReal() < that.getReal()) { + public static int compare(final Complex c1, final Complex c2) { + if (c1.getReal() < c2.getReal()) { return -1; } - if (fComplex.getReal() > that.getReal()) { + if (c1.getReal() > c2.getReal()) { return 1; } - long l1 = Double.doubleToLongBits(fComplex.getReal()); - long l2 = Double.doubleToLongBits(that.getReal()); + long l1 = Double.doubleToLongBits(c1.getReal()); + long l2 = Double.doubleToLongBits(c2.getReal()); if (l1 < l2) { return -1; } @@ -354,22 +354,22 @@ public int compareTo(final Complex that) { return 1; } - if (F.isZero(that.getImaginary())) { - if (!F.isZero(imDoubleValue())) { + if (F.isZero(c2.getImaginary())) { + if (!F.isZero(c1.getImaginary())) { return 1; } - } else if (F.isZero(imDoubleValue())) { + } else if (F.isZero(c1.getImaginary())) { return -1; } - if (fComplex.getImaginary() < that.getImaginary()) { + if (c1.getImaginary() < c2.getImaginary()) { return -1; } - if (fComplex.getImaginary() > that.getImaginary()) { + if (c1.getImaginary() > c2.getImaginary()) { return 1; } - l1 = Double.doubleToLongBits(fComplex.getImaginary()); - l2 = Double.doubleToLongBits(that.getImaginary()); + l1 = Double.doubleToLongBits(c1.getImaginary()); + l2 = Double.doubleToLongBits(c2.getImaginary()); if (l1 < l2) { return -1; } @@ -379,6 +379,10 @@ public int compareTo(final Complex that) { return 0; } + public int compareTo(final Complex that) { + return compare(fComplex, that); + } + /** * Compares this expression with the specified expression for order. Returns a negative integer, * zero, or a positive integer as this expression is canonical less than, equal to, or greater diff --git a/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/LinearAlgebraTestCase.java b/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/LinearAlgebraTestCase.java index 7753f5ddc1..5437414c7e 100644 --- a/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/LinearAlgebraTestCase.java +++ b/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/LinearAlgebraTestCase.java @@ -497,6 +497,10 @@ public void testEigensystem() { } public void testEigenvalues() { + check( + "Eigenvalues({{0,1,1,0,1,0,0,0},{1,0,0,1,0,1,0,0},{1,0,0,1,0,0,1,0},{0,1,1,0,0,0,0,1},{1,0,0,0,0,1,1,0},{0,1,0,0,1,0,0,1},{0,0,1,0,1,0,0,1},{0,0,0,1,0,1,1,0}})", // + "{-3.0,3.0,-1.0,-1.0,-1.0,1.0,1.0,1.0}"); + // print message: Eigenvalues: Sequence specification (+n,-n,{+n},{-n},{m,n}) or {m,n,s} // expected at position 2 in Eigenvalues({{1,0},{0,1}},{1,1,1,1}). check("Eigenvalues( {{1,0},{0,1}},{1,1,1,1})", //