historical-permutations
Version:
A library of historical permutation algorithms from 1950s-present implemented in JavaScript.
215 lines (206 loc) • 7.05 kB
JavaScript
const { cyclicModulo } = require("../utils/utils");
/* eslint no-loop-func: 0 */
function factorial(n) {
const factorialArray = Array.from({ length: n }, (value, index) => index + 1);
return factorialArray.reduce((factorialAccum, value) => {
return factorialAccum * value;
}, 1);
}
function sommervilleRotater(array, sizeToRotate, direction, position = -1) {
const arrayCopy = array.map(x => x);
const startOfRotation =
position === -1 ? array.length - sizeToRotate : position;
const endOfRotation =
position === -1 ? array.length - 1 : position + sizeToRotate - 1;
return arrayCopy.map((value, index) => {
if (index < startOfRotation || index > endOfRotation) {
return value;
}
const indexToExhangeWith =
startOfRotation +
cyclicModulo(index - startOfRotation + direction, sizeToRotate);
return array[indexToExhangeWith];
});
}
function sommerville1(n, startingDirection, cb) {
let permutation = Array.from({ length: n }, (value, index) => index + 1);
const radixReference = Array.from({ length: n }, (value, index) => {
if (index === 0) return 2;
if (index === 1) return 3;
return factorial(index + 1);
});
let radixArray = Array.from({ length: n }, () => 0);
let radixChecker = false;
let initializer = true;
let direction = startingDirection;
let i = 0;
while (radixChecker === false) {
let directionChange = false;
radixArray = radixArray.map((value, index) => i % radixReference[index]);
radixArray.forEach((radixValue, radixIndex) => {
if (radixIndex === 0 && i > 0) {
permutation = sommervilleRotater(permutation, 3, direction, n - 3);
}
if (radixIndex > 0 && i > 0) {
const amountToRotate =
radixIndex === 1 ? radixIndex + 1 : radixIndex + 2;
if (radixValue === 0) {
permutation = sommervilleRotater(
permutation,
amountToRotate,
direction
);
directionChange = true;
}
}
});
if (directionChange) direction *= -1;
i += 1;
radixChecker = radixArray.every(
radix => radix === 0 && initializer === false
);
if (radixChecker === false) cb(permutation);
if (initializer === true) initializer = false;
}
}
function sommerville2(n, direction, cb) {
let permutation = Array.from({ length: n }, (value, index) => index + 1);
const radixReference = Array.from({ length: n }, (value, index) => {
if (index === 0) return 2;
if (index === 1) return 3;
return factorial(index + 1);
});
let radixArray = Array.from({ length: n }, () => 0);
let radixChecker = false;
let initializer = true;
let i = 0;
let currentDirection = direction;
while (radixChecker === false) {
radixArray = radixArray.map((value, index) => i % radixReference[index]);
radixArray.forEach((radixValue, radixIndex) => {
if (radixIndex === 1 && i > 0) {
if (radixValue === 0) currentDirection *= -1;
permutation = sommervilleRotater(permutation, 3, currentDirection);
if (radixValue === 2) {
permutation = sommervilleRotater(permutation, 2, currentDirection);
}
}
if (radixIndex > 1 && i > 0 && radixValue === 0) {
const amountToRotate = radixIndex + 2;
permutation = sommervilleRotater(
permutation,
amountToRotate,
currentDirection
);
}
});
i += 1;
radixChecker = radixArray.every(
radix => radix === 0 && initializer === false
);
if (radixChecker === false) cb(permutation);
if (initializer === true) initializer = false;
}
}
function sommerville3(n, direction, cb) {
let permutation = Array.from({ length: n }, (value, index) => index + 1);
const radixReference = Array.from({ length: n }, (value, index) => {
return index === 0 ? 2 : factorial(index + 2);
});
let radixArray = Array.from({ length: n - 1 }, () => 0);
let radixChecker = false;
let initializer = true;
let i = 0;
while (radixChecker === false) {
radixArray = radixArray.map((value, index) => i % radixReference[index]);
radixArray.forEach((radixValue, radixIndex) => {
if (radixIndex > 0 && i > 0 && radixValue === 0) {
const amountToRotate = radixIndex + 3;
permutation = sommervilleRotater(
permutation,
amountToRotate,
direction * -1
);
}
if (radixIndex === 0 && i > 0) {
permutation = sommervilleRotater(permutation, 2, direction, n - 3);
if (radixValue === 0) {
permutation = sommervilleRotater(permutation, 3, direction, n - 3);
}
}
});
i += 1;
radixChecker = radixArray.every(
radix => radix === 0 && initializer === false
);
if (radixChecker === false) cb(permutation);
if (initializer === true) initializer = false;
}
}
function sommerville4(n, direction, cb) {
let permutation = Array.from({ length: n }, (value, index) => index + 1);
const radixReference = Array.from({ length: n }, (value, index) => {
if (index === 0) return 2;
if (index === 1) return 3;
return factorial(index + 1);
});
let radixArray = Array.from({ length: n }, () => 0);
let radixChecker = false;
let initializer = true;
let i = 0;
let currentDirection = direction;
cb(permutation);
while (radixChecker === false) {
radixArray = radixArray.map((value, index) => i % radixReference[index]);
radixChecker = radixArray.every(
(radix, checkerIndex) =>
radix === radixReference[checkerIndex] - 1 && initializer === false
);
if (radixChecker === true) break;
radixArray.forEach((radixValue, radixIndex) => {
if (radixIndex === 1) {
permutation = sommervilleRotater(permutation, 3, currentDirection);
if (radixValue === 0) {
permutation = sommervilleRotater(permutation, 2, currentDirection);
currentDirection *= -1;
}
}
if (
radixIndex > 1 &&
i > 0 &&
radixValue === radixReference[radixIndex] - 1
) {
const amountToRotate = radixIndex + 2;
permutation = sommervilleRotater(
permutation,
amountToRotate,
currentDirection
);
}
});
i += 1;
if (radixChecker === false) cb(permutation);
if (initializer === true) initializer = false;
}
}
function gysinSommerville(n, algorithm, variable) {
const outputArrays = [];
if (algorithm === 1)
sommerville1(n, variable, finishedArray =>
outputArrays.push(finishedArray)
);
if (algorithm === 2)
sommerville2(n, variable, finishedArray =>
outputArrays.push(finishedArray)
);
if (algorithm === 3)
sommerville3(n, variable, finishedArray =>
outputArrays.push(finishedArray)
);
if (algorithm === 4)
sommerville4(n, variable, finishedArray =>
outputArrays.push(finishedArray)
);
return outputArrays;
}
module.exports = { sommervilleRotater, gysinSommerville };