NX01: Added adult size lehmer codes test case
All checks were successful
Run test asserts / Test-Asserts (push) Successful in 1m2s

This commit is contained in:
Willem Cazander 2026-01-29 21:14:52 +01:00
parent 6d3133be55
commit 878bf524da

View file

@ -72,17 +72,23 @@ public class NumberMatrixFactoryTest {
// size: 9 result: 362880 (T512) (larger than max of 18 bit nether slug path) // size: 9 result: 362880 (T512) (larger than max of 18 bit nether slug path)
// size: 10 result: 3628800 // size: 10 result: 3628800
// size: 11 result: 39916800 // size: 11 result: 39916800
// java.lang.OutOfMemoryError: Java heap space // size: 12 result: 479001600
// for (int i = 5; i < 10; i++) { // size: 13 result: 6227020800
// int n = i; // size: 14 result: 87178291200
// int[] initial = new int[n]; // size: 15 result: 1307674368000
// for (int ni = 0; ni < n; ni++) { // size: 16 result: 20922789888000
// initial[ni] = ni; // size: 17 result: 355687428096000
// } // size: 18 result: 6402373705728000
// List<int[]> allPermutations = new ArrayList<>(); // size: 19 result: 121645100408832000
// generatePermutations(initial, 0, allPermutations); // size: 20 result: 2432902008176640000
// System.out.println("size: " + i + " result: " + allPermutations.size()); // size: 21 result: -4249290049419214848 TODO: use BigInteger or limit to 18 bit
// } for (int i = 5; i < 20; i++) {
int[] rankFirst = calculateLehmerFromRank(0, i);
long amount = calculateTotalPermutations(rankFirst);
String IDLE = Arrays.toString(decodeLehmerCode(rankFirst));
String IDBE = Arrays.toString(decodeLehmerCode(calculateLehmerFromRank(amount - 1, i)));
System.out.println("size: " + i + " result: " + amount + " IDLE: " + IDLE + " IDBE: " + IDBE);
}
} }
// TODO: redo matrix with lehmer dial tones from jpp-nether-dial-lehmer // TODO: redo matrix with lehmer dial tones from jpp-nether-dial-lehmer
@ -260,4 +266,108 @@ public class NumberMatrixFactoryTest {
Assertions.assertArrayEquals(originalLehmer, reconstructedLehmer, "The inverse operation should perfectly reconstruct the Lehmer code."); Assertions.assertArrayEquals(originalLehmer, reconstructedLehmer, "The inverse operation should perfectly reconstruct the Lehmer code.");
} }
/**
* Calculates the total number of permutations (n!) for a set of size n. The size n is equivalent to the length of the Lehmer code.
*/
public long calculateTotalPermutations(int[] lehmerCode) {
int n = lehmerCode.length;
long factorial = 1;
for (int i = 1; i <= n; i++) {
factorial *= i;
}
return factorial;
}
@Test
public void testPermutationCountFromLehmerCode() {
// Case 1: Lehmer code for [1, 2, 3] is [0, 0, 0]. Length = 3.
// Total permutations = 3! = 6.
int[] code1 = { 0, 0, 0 };
Assertions.assertEquals(6, calculateTotalPermutations(code1), "3-element set should have 6 permutations");
// Case 2: Lehmer code for [3, 1, 2] is [2, 0, 0]. Length = 3.
// Total permutations = 3! = 6.
int[] code2 = { 2, 0, 0 };
Assertions.assertEquals(6, calculateTotalPermutations(code2), "Lehmer code [2, 0, 0] represents 6 total permutations");
// Case 3: Lehmer code for [4, 3, 2, 1] is [3, 2, 1, 0]. Length = 4.
// Total permutations = 4! = 24.
int[] code3 = { 3, 2, 1, 0 };
Assertions.assertEquals(24, calculateTotalPermutations(code3), "4-element set should have 24 permutations");
}
/**
* Calculates the lexicographical rank (0-based) from a Lehmer code. Logic: sum(lehmer[i] * (n - 1 - i)!)
*/
public long calculateRank(int[] lehmerCode) {
int n = lehmerCode.length;
long rank = 0;
for (int i = 0; i < n; i++) {
rank += (long) lehmerCode[i] * factorial(n - 1 - i);
}
return rank;
}
private long factorial(int n) {
if (n <= 1) {
return 1;
}
long fact = 1;
for (int i = 2; i <= n; i++) {
fact *= i;
}
return fact;
}
@Test
public void testRankAndTotalPermutations() {
// Example: Permutation {1, 0, 2} has Lehmer code {1, 0, 0}
// Rank = 1 * 2! + 0 * 1! + 0 * 0! = 2
int[] lehmer1 = { 1, 0, 0 };
Assertions.assertEquals(2, calculateRank(lehmer1), "Rank of {1, 0, 0} should be 2");
// Example: Permutation {2, 1, 0} (Last permutation) has Lehmer code {2, 1, 0}
// Rank = 2 * 2! + 1 * 1! + 0 * 0! = 4 + 1 + 0 = 5
int[] lehmer2 = { 2, 1, 0 };
Assertions.assertEquals(5, calculateRank(lehmer2), "Rank of {2, 1, 0} should be 5");
// Example: Identity {0, 1, 2, 3} has Lehmer code {0, 0, 0, 0}
// Rank = 0
int[] lehmer3 = { 0, 0, 0, 0 };
Assertions.assertEquals(0, calculateRank(lehmer3), "Identity permutation always has rank 0");
}
/**
* Converts a lexicographical rank (0-based) into a Lehmer code. Logic: Repeatedly divide rank by (n-1-i)! and keep the quotient as the digit.
*/
public int[] calculateLehmerFromRank(long rank, int n) {
int[] lehmer = new int[n];
for (int i = 0; i < n; i++) {
long fact = factorial(n - 1 - i);
lehmer[i] = (int) (rank / fact);
rank %= fact;
}
return lehmer;
}
@Test
public void testLehmerFromRank() {
// Rank 0 should always return all zeros (Identity)
Assertions.assertArrayEquals(new int[] { 0, 0, 0 }, calculateLehmerFromRank(0, 3));
// For n=3, rank 2:
// Digit 1: 2 / 2! = 1 (rem 0)
// Digit 2: 0 / 1! = 0 (rem 0)
// Digit 3: 0 / 0! = 0
// Result: {1, 0, 0}
Assertions.assertArrayEquals(new int[] { 1, 0, 0 }, calculateLehmerFromRank(2, 3));
// For n=3, rank 5 (the very last permutation):
// Digit 1: 5 / 2! = 2 (rem 1)
// Digit 2: 1 / 1! = 1 (rem 0)
// Digit 3: 0 / 0! = 0
// Result: {2, 1, 0}
Assertions.assertArrayEquals(new int[] { 2, 1, 0 }, calculateLehmerFromRank(5, 3));
}
} }