From b0a383bf1243233fc3421dadaac0d86524a43323 Mon Sep 17 00:00:00 2001 From: axexlck Date: Mon, 4 Nov 2024 00:23:11 +0100 Subject: [PATCH] Improve IntegerPartitions see: - https://github.com/Mathics3/mathics-core/blob/715d9c0cef7e943230e613ca0964fc40f4e8feaa/mathics/builtin/numbers/numbertheory.py#L450 --- .../core/builtin/Combinatoric.java | 59 ++++++++++++++- .../org/matheclipse/core/expression/F.java | 17 +++++ .../core/system/CombinatoricTestCase.java | 74 +++++++++++++++++++ 3 files changed, 147 insertions(+), 3 deletions(-) diff --git a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/Combinatoric.java b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/Combinatoric.java index 5ea479103..891e87ac1 100644 --- a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/Combinatoric.java +++ b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/Combinatoric.java @@ -7,7 +7,6 @@ import java.util.Map; import java.util.Set; import org.matheclipse.core.basic.Config; -import org.matheclipse.core.basic.OperationSystem; import org.matheclipse.core.combinatoric.KPartitionsIterable; import org.matheclipse.core.combinatoric.KPartitionsList; import org.matheclipse.core.combinatoric.KSubsetsIterable; @@ -821,7 +820,39 @@ public IExpr evaluate(final IAST ast, EvalEngine engine) { max = range.maximum(); } if (ast.isAST3()) { - return frobeniusPartition(ast, engine); + IExpr kspec = ast.arg2(); + if (ast.arg3().equals(S.All)) { + // IntegerPartitions(n_Integer, kspec_, All) := IntegerPartitions(n, kspec) + return F.IntegerPartitions(F.ZZ(n), kspec); + } + if (ast.arg3().isList()) { + IAST s = (IAST) ast.arg3(); + if (kspec.isList1() && kspec.first().isInteger()) { + IInteger k = (IInteger) kspec.first(); + // "IntegerPartitions(n_Integer, {k_Integer}, s_List) := + // ReverseSort@Select(Union(ReverseSort /@ Tuples(s, k)), Total(#) == n &), + return F.ReverseSort(F.Select(F.Union(F.Map(S.ReverseSort, F.Tuples(s, k))), + F.Function(F.Equal(F.Total(F.Slot1), n)))); + } + if (!s.forAll(x -> x.isInteger() && x.isPositive())) { + return F.NIL; + } + } + IExpr frobeniusPartition = frobeniusPartition(ast, engine); + if (frobeniusPartition.isList()) { + IASTMutable mutableList = ((IAST) frobeniusPartition).copy(); + EvalAttributes.sort(mutableList, + Comparators.reversedComparator(Comparators.LEXICAL_COMPARATOR)); + return mutableList; + } + return F.NIL; + } else if (ast.argSize() == 4) { + IExpr kspec = ast.arg2(); + IExpr sspec = ast.arg3(); + IExpr m = ast.arg4(); + // "IntegerPartitions(n_Integer, kspec_, sspec_, m_) := Take(IntegerPartitions(n, k, + // sspec), m)", + return F.Take(F.IntegerPartitions(F.ZZ(n), kspec, sspec), m); } if (n == 0) { @@ -979,10 +1010,11 @@ private static boolean createFrobeniusSolution(IInteger[] frobeniusSolution, @Override public int[] expectedArgSize(IAST ast) { - return ARGS_1_3; + return ARGS_1_4; } } + /** * * @@ -1055,6 +1087,7 @@ public int[] expectedArgSize(IAST ast) { public void setUp(final ISymbol newSymbol) {} } + private static final class KOrderlessPartitions extends AbstractFunctionEvaluator { /** {@inheritDoc} */ @@ -1157,6 +1190,7 @@ private IAST createSinglePartition(final IAST listArg0, final ISymbol symbol, } } + /** * Generate a list of all all k-partitions for a given list with N elements.
* See Wikipedia - Partition of a @@ -1189,6 +1223,7 @@ public int[] expectedArgSize(IAST ast) { } } + /** * * @@ -1256,6 +1291,7 @@ public int[] expectedArgSize(IAST ast) { public void setUp(final ISymbol newSymbol) {} } + /** * * @@ -1352,6 +1388,7 @@ public int[] expectedArgSize(IAST ast) { } } + /** * * @@ -1474,6 +1511,7 @@ public int[] expectedArgSize(IAST ast) { } } + /** * * @@ -1540,6 +1578,7 @@ public int[] expectedArgSize(IAST ast) { } } + /** * * @@ -1595,6 +1634,7 @@ public int[] expectedArgSize(IAST ast) { } } + /** * * @@ -1699,6 +1739,7 @@ public int[] expectedArgSize(IAST ast) { } } + /** * * @@ -1754,6 +1795,7 @@ public int[] expectedArgSize(IAST ast) { } } + /** * * @@ -1852,6 +1894,7 @@ public int[] expectedArgSize(IAST ast) { } } + /** * * @@ -2068,6 +2111,7 @@ private IAST createPermutationsWithNParts(final IAST list, int parts, } } + private static final class PolygonalNumber extends AbstractFunctionEvaluator { @Override @@ -2093,6 +2137,7 @@ public void setUp(final ISymbol newSymbol) { } } + /** * * @@ -2174,6 +2219,7 @@ public int[] expectedArgSize(IAST ast) { public void setUp(final ISymbol newSymbol) {} } + /** * * @@ -2250,6 +2296,7 @@ public int[] expectedArgSize(IAST ast) { public void setUp(final ISymbol newSymbol) {} } + /** * * @@ -2316,6 +2363,7 @@ public int[] expectedArgSize(IAST ast) { } } + /** * * @@ -2397,6 +2445,7 @@ public void setUp(final ISymbol newSymbol) { } } + /** * * @@ -2585,6 +2634,7 @@ public static KSubsetsList createKSubsets(final IAST list, final int k, IAST res } } + /** * * @@ -2734,6 +2784,7 @@ private void tuplesOfListsRecursive(final IAST originalList, final int k, IASTAp } } + /** * * @@ -2815,6 +2866,7 @@ public int[] expectedArgSize(IAST ast) { public void setUp(final ISymbol newSymbol) {} } + /** * Generate an java.lang.Iterable for (multiset) permutations * @@ -2965,6 +3017,7 @@ public KPermutationsIterable(final int[] data, final int len, final int parts) { public Iterator iterator() { return new KPermutationsIterator(); } + } /** diff --git a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/expression/F.java b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/expression/F.java index 2bc3327c3..bdb013f8f 100644 --- a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/expression/F.java +++ b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/expression/F.java @@ -5318,6 +5318,10 @@ public static IAST IntegerPart(final IExpr a0) { return new AST1(IntegerPart, a0); } + public static IAST IntegerPartitions(final IExpr n, final IExpr k) { + return new AST2(IntegerPartitions, n, k); + } + public static IAST IntegerPartitions(final IExpr n, final IExpr k, final IExpr p) { return new AST3(IntegerPartitions, n, k, p); } @@ -9017,6 +9021,10 @@ public static IAST Reverse(final IExpr a) { return new AST1(Reverse, a); } + public static IAST ReverseSort(final IExpr a) { + return new AST1(ReverseSort, a); + } + public static IAST RomanNumeral(final IExpr a) { return new AST1(RomanNumeral, a); } @@ -9808,6 +9816,11 @@ public static IExpr subst(IExpr expr, IExpr subExpr, IExpr replacementExpr) { .orElse(expr); } + public static IAST SubsetQ(IExpr x, IExpr y) { + return new AST2(S.SubsetQ, x, y); + } + + /** * Return x + (-1)*y * @@ -10648,6 +10661,10 @@ public static IAST TrueQ(final IExpr expr) { return new AST1(TrueQ, expr); } + public static IAST Tuples(final IExpr x, final IExpr y) { + return new AST2(Tuples, x, y); + } + /** * Create a function head(arg) with 1 argument without evaluation. * diff --git a/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/CombinatoricTestCase.java b/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/CombinatoricTestCase.java index ea5db3782..b4bba226b 100644 --- a/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/CombinatoricTestCase.java +++ b/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/CombinatoricTestCase.java @@ -100,6 +100,80 @@ public void testFindPermutation() { "Cycles({{2,3},{4,6,5}})"); } + @Test + public void testIntegerPartitions() { + // TODO + check("IntegerPartitions(1,7,{-1,-2,3})", // + "IntegerPartitions(1,7,{-1,-2,3})"); + + check("IntegerPartitions(8, All, {1, 2, 5})", // + "{{5,2,1},{5,1,1,1},{2,2,2,2},{2,2,2,1,1},{2,2,1,1,1,1},{2,1,1,1,1,1,1},{1,1,1,1,\n" // + + "1,1,1,1}}"); + + check("IntegerPartitions(5)", // + "{{5},{4,1},{3,2},{3,1,1},{2,2,1},{2,1,1,1},{1,1,1,1,1}}"); + check("IntegerPartitions(8,3)", // + "{{8},{7,1},{6,2},{6,1,1},{5,3},{5,2,1},{4,4},{4,3,1},{4,2,2},{3,3,2}}"); + check("IntegerPartitions(8,{3})", // + "{{6,1,1},{5,2,1},{4,3,1},{4,2,2},{3,3,2}}"); + check("IntegerPartitions(8, All, {1, 2, 5})", // + "{{5,2,1},{5,1,1,1},{2,2,2,2},{2,2,2,1,1},{2,2,1,1,1,1},{2,1,1,1,1,1,1},{1,1,1,1,\n" // + + "1,1,1,1}}"); + check("IntegerPartitions(8, All, All, 3)", // + "{{8},{7,1},{6,2}}"); + check("IntegerPartitions(4, {2}, {-1, 0, 1, 4, 5})", // + "{{5,-1},{4,0}}"); + + // message Maximum AST dimension 2147483647 exceededs + check("IntegerPartitions(2147483647)", // + "IntegerPartitions(2147483647)"); + + // TODO improve performance + // check("IntegerPartitions(1009,2)", // + // "{{1009}}"); + check("IntegerPartitions(1009,1)", // + "{{1009}}"); + check("IntegerPartitions(1009,0)", // + "{}"); + + check("IntegerPartitions(50, All, {6, 9, 20})", // + "{{20,9,9,6,6},{20,6,6,6,6,6}}"); + // https://oeis.org/A214772 - McNugget partitions - Number of partitions of n into parts 6, 9 or + // 20. + check("Table(Length(IntegerPartitions(i, All, {6, 9, 20})), {i,0, 100, 1})", // + "{1,0,0,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,2,0,1,1,0,0,2,0,1,2,0,1,2,0,1,2,0,1,3,0,2,2,\n" + + "1,1,3,0,2,3,1,2,3,1,2,3,1,2,4,1,3,3,2,2,5,1,3,4,2,3,5,2,3,5,2,3,6,2,4,5,3,3,7,2,\n" + + "5,6,3,4,7,3,5,7,3,5,8,3,6,7,4,5,9,3,7,8,5}"); + + // check("IntegerPartitions(50, All, {6, 9, 20})", // + // "{{20,9,9,6,6},{20,6,6,6,6,6}}"); + check("IntegerPartitions(156, {9,10}, {1, 5, 10, 25})", // + "{{25,25,25,25,25,10,10,10,1},{25,25,25,25,25,10,10,5,5,1}}"); + check("IntegerPartitions(156, 10, {1, 5, 10, 25})", // + "{{25,25,25,25,25,25,5,1},{25,25,25,25,25,10,10,10,1},{25,25,25,25,25,10,10,5,5,1}}"); + check("IntegerPartitions(4)", // + "{{4},{3,1},{2,2},{2,1,1},{1,1,1,1}}"); + check("IntegerPartitions(6)", // + "{{6},{5,1},{4,2},{4,1,1},{3,3},{3,2,1},{3,1,1,1},{2,2,2},{2,2,1,1},{2,1,1,1,1},{\n" // + + "1,1,1,1,1,1}}"); + check("IntegerPartitions(6, {3,4})", // + "{{4,1,1},{3,2,1},{3,1,1,1},{2,2,2},{2,2,1,1}}"); + check("IntegerPartitions(10,2)", // + "{{10},{9,1},{8,2},{7,3},{6,4},{5,5}}"); + check("IntegerPartitions(10,{2})", // + "{{9,1},{8,2},{7,3},{6,4},{5,5}}"); + check("IntegerPartitions(0)", // + "{{}}"); + check("IntegerPartitions(1)", // + "{{1}}"); + check("IntegerPartitions(-1)", // + "{}"); + check("IntegerPartitions(.5)", // + "IntegerPartitions(0.5)"); + check("IntegerPartitions(1/2)", // + "{}"); + } + @Test public void testPermute() { check("Permute(CharacterRange(\"v\", \"z\"), Cycles({{1, 5, 3}}))", //