ultra-mega-enumerator
Version:
Ultra Mega Enumerator is a lightweight library designed to enumerate various combinatorial objects.
599 lines • 23.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Sequence = exports.Combiner = exports.Operation = void 0;
const Numbers_1 = require("../Numbers");
// Define Operation Enum
var Operation;
(function (Operation) {
Operation["Add"] = "Add";
Operation["Subtract"] = "Subtract";
Operation["Multiply"] = "Multiply";
Operation["Divide"] = "Divide";
Operation["X"] = "X";
Operation["Y"] = "Y";
Operation["Power"] = "Power";
Operation["Log"] = "Log";
Operation["Min"] = "Min";
Operation["Max"] = "Max";
Operation["Modulo"] = "Modulo";
Operation["Bounce"] = "Bounce";
Operation["Distance"] = "Distance";
Operation["And"] = "And";
Operation["Nand"] = "Nand";
Operation["Or"] = "Or";
Operation["Nor"] = "Nor";
Operation["Implication"] = "Implication";
Operation["ReverseImplication"] = "ReverseImplication";
Operation["Xor"] = "Xor";
Operation["Xnor"] = "Xnor";
Operation["ShiftBits"] = "ShiftBits";
Operation["ProjectBits"] = "ProjectBits";
Operation["LCM"] = "LCM";
Operation["GCD"] = "GCD";
Operation["Equal"] = "Equal";
Operation["NotEqual"] = "NotEqual";
Operation["LessThan"] = "LessThan";
Operation["LessThanOrEqual"] = "LessThanOrEqual";
Operation["GreaterThan"] = "GreaterThan";
Operation["GreaterThanOrEqual"] = "GreaterThanOrEqual";
Operation["Binomial"] = "Binomial";
Operation["ExpandBits"] = "ExpandBits";
Operation["ExpandBitsFill"] = "ExpandBitsFill";
Operation["CantorIntervalBinaryNumber"] = "CantorIntervalBinaryNumber";
Operation["PermuteBits"] = "PermuteBits";
Operation["HardThreshold"] = "HardThreshold";
Operation["RandInt"] = "RandInt";
Operation["IterateBetween"] = "IterateBetween";
Operation["Bits"] = "Bits";
Operation["Trits"] = "Trits";
Operation["TritAnd"] = "TritAnd";
Operation["TritNand"] = "TritNand";
Operation["TritOr"] = "TritOr";
Operation["TritNor"] = "TritNor";
Operation["TritCons"] = "TritCons";
Operation["TritNcons"] = "TritNcons";
Operation["TritAny"] = "TritAny";
Operation["TritNany"] = "TritNany";
Operation["TritMul"] = "TritMul";
Operation["TritNmul"] = "TritNmul";
Operation["TritSum"] = "TritSum";
Operation["TritNsum"] = "TritNsum";
})(Operation || (exports.Operation = Operation = {}));
// Define Combiner Enum
var Combiner;
(function (Combiner) {
Combiner["Product"] = "Product";
Combiner["SwappedProduct"] = "SwappedProduct";
Combiner["Divisive"] = "Divisive";
Combiner["Convolution"] = "Convolution";
Combiner["Triangular"] = "Triangular";
Combiner["SwappedTriangular"] = "SwappedTriangular";
Combiner["Recycle"] = "Recycle";
Combiner["Apply"] = "Apply";
Combiner["MixedRadix"] = "Mixed Radix";
})(Combiner || (exports.Combiner = Combiner = {}));
function maxBinaryDigits(a, b) {
const absA = Math.abs(a);
const absB = Math.abs(b);
// Special case: 0 requires 1 digit
const digitsA = absA === 0 ? 1 : Math.floor(Math.log2(absA)) + 1;
const digitsB = absB === 0 ? 1 : Math.floor(Math.log2(absB)) + 1;
return Math.max(digitsA, digitsB);
}
function maxTernaryDigits(a, b) {
const absA = Math.abs(a);
const absB = Math.abs(b);
// For balanced ternary, max value in n digits is (3^n - 1) / 2
// So to represent value v, we need n such that v <= (3^n - 1) / 2
// Which means 3^n >= 2*v + 1, so n >= log_3(2*v + 1)
const digitsA = absA === 0 ? 1 : Math.ceil(Math.log(2 * absA + 1) / Math.log(3));
const digitsB = absB === 0 ? 1 : Math.ceil(Math.log(2 * absB + 1) / Math.log(3));
return Math.max(digitsA, digitsB);
}
function applyBitwise(x, y, op) {
const nbdigits = maxBinaryDigits(x, y);
const bx = Numbers_1.Numbers.toBinary(x, nbdigits);
const by = Numbers_1.Numbers.toBinary(y, nbdigits);
// Map -1/1 to true, 0 to false
const boolx = bx.map(bit => bit !== 0);
const booly = by.map(bit => bit !== 0);
// Apply the boolean operation bitwise
const resultBool = boolx.map((b, i) => op(b, booly[i]));
// Map booleans back to 1 (true) and 0 (false)
const resultBits = resultBool.map(b => b ? 1 : 0);
let signX = Math.sign(x);
signX = signX === 0 ? 1 : signX;
let signY = Math.sign(y);
signY = signY === 0 ? 1 : signY;
// The sign is the product of the signs of x and y
const sign = signX * signY;
// Convert back to integer
const result = sign * Numbers_1.Numbers.fromBinary(resultBits);
return result == -0 ? 0 : result;
}
function sign(n) {
return n > 0 ? 1 : (n < 0 ? -1 : 0);
}
const binaryTritOps = {
AND: [[-1, -1, -1], [-1, 0, 0], [-1, 0, 1]],
NAND: [[1, 1, 1], [1, 0, 0], [1, 0, -1]],
OR: [[-1, 0, 1], [0, 0, 1], [1, 1, 1]],
NOR: [[1, 0, -1], [0, 0, -1], [-1, -1, -1]],
CONS: [[-1, 0, 0], [0, 0, 0], [0, 0, 1]],
NCONS: [[1, 0, 0], [0, 0, 0], [0, 0, -1]],
ANY: [[-1, -1, 0], [-1, 0, 1], [0, 1, 1]],
NANY: [[1, 1, 0], [1, 0, -1], [0, -1, -1]],
MUL: [[1, 0, -1], [0, 0, 0], [-1, 0, 1]],
NMUL: [[-1, 0, 1], [0, 0, 0], [1, 0, -1]],
SUM: [[1, -1, 0], [-1, 0, 1], [0, 1, -1]],
NSUM: [[-1, 1, 0], [1, 0, -1], [0, -1, 1]],
};
function applyTritwiseBinary(x, y, tritOp) {
const ndigits = maxTernaryDigits(x, y);
const tx = Numbers_1.Numbers.toBalancedTernary(x, ndigits);
const ty = Numbers_1.Numbers.toBalancedTernary(y, ndigits);
const result = tx.map((t, i) => tritOp[Numbers_1.Numbers.tritIndex.get(t)][Numbers_1.Numbers.tritIndex.get(ty[i])]);
return Numbers_1.Numbers.fromBalancedTernary(result);
}
/**
* Shifts the bits of a number left or right using Numbers.toBinary and Numbers.fromBinary.
* @param n The number to shift.
* @param positions The number of positions to shift (positive = left, negative = right).
* @returns The shifted number.
*/
function shift(n, positions) {
if (positions === 0)
return n;
if (positions > 0) {
return n * Math.pow(2, positions);
}
else {
// Arithmetic shift for negative numbers, logical for positive
return n >= 0
? Math.floor(n / Math.pow(2, -positions))
: -Math.floor(Math.abs(n) / Math.pow(2, -positions));
}
}
function bounce(n, limit) {
if (limit === 0)
return 0;
const distance = Math.abs(limit);
const period = distance * 2;
const normalized = n - Math.floor(n / period) * period;
const value = normalized <= distance
? normalized
: period - normalized;
return value == 0 ? 0 : Math.sign(limit) * value;
}
function projectBits(a, b) {
const absA = Math.abs(a);
const absB = Math.abs(b);
const nbDigits = absB == 0 ? 1 : (Math.floor(Math.log(absB) / Math.log(2)) + 1);
const binA = Numbers_1.Numbers.toBinary(absA, nbDigits);
const binB = Numbers_1.Numbers.toBinary(absB, nbDigits);
const oArr = new Array(nbDigits).fill(0);
let cursor = 0;
for (let i = nbDigits - 1; i >= 0; i--) {
if (binB[i] == 1) {
if (cursor < binA.length && binA[nbDigits - cursor++ - 1] == 1) {
oArr[i] = 1;
}
}
}
const o = Numbers_1.Numbers.fromBinary(oArr);
let signA = Math.sign(a);
signA = signA === 0 ? 1 : signA;
let signB = Math.sign(b);
signB = signB === 0 ? 1 : signB;
// The sign is the product of the signs of x and y
const sign = signA * signB;
return o * sign === -0 ? 0 : o * sign;
}
const ops = new Map([
[Operation.Add, (x, y) => [x + y]],
[Operation.Subtract, (x, y) => [x - y]],
[Operation.Multiply, (x, y) => [x * y]],
[Operation.Divide, (x, y) => [y !== 0 ? Math.floor(x / y) : 0]],
[Operation.X, (x, y) => [x]],
[Operation.Y, (x, y) => [y]],
[Operation.Power, (x, y) => [Math.round(Math.pow(x, y))]],
[Operation.Log, (x, y) => [y > 1 && x > 0 ? Math.floor(Math.log(x) / Math.log(y)) : 0]],
[Operation.Min, (x, y) => [Math.min(x, y)]],
[Operation.Max, (x, y) => [Math.max(x, y)]],
[Operation.Modulo, (x, y) => [y !== 0 ? x - Math.floor(x / y) * y : 0]],
[Operation.Bounce, (x, y) => [bounce(x, y)]],
[Operation.Distance, (x, y) => [Math.abs(y - x)]],
[Operation.And, (x, y) => [applyBitwise(x, y, (a, b) => a && b)]],
[Operation.Nand, (x, y) => [applyBitwise(x, y, (a, b) => !(a && b))]],
[Operation.Or, (x, y) => [applyBitwise(x, y, (a, b) => a || b)]],
[Operation.Nor, (x, y) => [applyBitwise(x, y, (a, b) => !(a || b))]],
[Operation.Implication, (x, y) => [applyBitwise(x, y, (a, b) => (!a) || b)]],
[Operation.ReverseImplication, (x, y) => [applyBitwise(x, y, (a, b) => (!b) || a)]],
[Operation.Xor, (x, y) => [applyBitwise(x, y, (a, b) => a !== b)]],
[Operation.Xnor, (x, y) => [applyBitwise(x, y, (a, b) => a === b)]],
[Operation.ShiftBits, (x, y) => [shift(x, y)]],
[Operation.ProjectBits, (x, y) => [projectBits(x, y)]],
[Operation.LCM, (x, y) => [Numbers_1.Numbers.lcm(x, y)]],
[Operation.GCD, (x, y) => [Numbers_1.Numbers.gcd(x, y)]],
[Operation.Equal, (x, y) => [(x === y ? 1 : 0)]],
[Operation.NotEqual, (x, y) => [(x !== y ? 1 : 0)]],
[Operation.LessThan, (x, y) => [(x < y ? 1 : 0)]],
[Operation.LessThanOrEqual, (x, y) => [(x <= y ? 1 : 0)]],
[Operation.GreaterThan, (x, y) => [(x > y ? 1 : 0)]],
[Operation.GreaterThanOrEqual, (x, y) => [(x >= y ? 1 : 0)]],
[Operation.Binomial, (x, y) => [Numbers_1.Numbers.binomial(x, y)]],
[Operation.ExpandBits, (x, y) => [Numbers_1.Numbers.expandBits(x, y, '0')]],
[Operation.ExpandBitsFill, (x, y) => [Numbers_1.Numbers.expandBits(x, y, 'bit')]],
[Operation.CantorIntervalBinaryNumber, (x, y) => [Numbers_1.Numbers.CantorIntervalBinaryNumber(x, y)]],
[Operation.PermuteBits, (x, y) => [Numbers_1.Numbers.permuteBits(x, y)]],
[Operation.HardThreshold, (x, y) => [Math.abs(x) > Math.abs(y) ? 0 : x]],
[Operation.RandInt, (x, y) => {
let a = Math.min(x, y);
let b = Math.max(x, y);
return [Math.floor(a + (Math.random() * (b - a + 1)))];
}],
[Operation.IterateBetween, (x, y) => {
let d = Math.abs(y - x);
let delta = 1;
if (y < x)
delta = -1;
const o = [];
for (let j = 0; j < d; j++) {
o.push(x + j * delta);
}
return o;
}],
[Operation.Bits, (x, y) => Numbers_1.Numbers.toBinary(x, y)],
[Operation.Trits, (x, y) => Numbers_1.Numbers.toBalancedTernary(x, y)],
[Operation.TritAnd, (x, y) => [applyTritwiseBinary(x, y, binaryTritOps.AND)]],
[Operation.TritNand, (x, y) => [applyTritwiseBinary(x, y, binaryTritOps.NAND)]],
[Operation.TritOr, (x, y) => [applyTritwiseBinary(x, y, binaryTritOps.OR)]],
[Operation.TritNor, (x, y) => [applyTritwiseBinary(x, y, binaryTritOps.NOR)]],
[Operation.TritCons, (x, y) => [applyTritwiseBinary(x, y, binaryTritOps.CONS)]],
[Operation.TritNcons, (x, y) => [applyTritwiseBinary(x, y, binaryTritOps.NCONS)]],
[Operation.TritAny, (x, y) => [applyTritwiseBinary(x, y, binaryTritOps.ANY)]],
[Operation.TritNany, (x, y) => [applyTritwiseBinary(x, y, binaryTritOps.NANY)]],
[Operation.TritMul, (x, y) => [applyTritwiseBinary(x, y, binaryTritOps.MUL)]],
[Operation.TritNmul, (x, y) => [applyTritwiseBinary(x, y, binaryTritOps.NMUL)]],
[Operation.TritSum, (x, y) => [applyTritwiseBinary(x, y, binaryTritOps.SUM)]],
[Operation.TritNsum, (x, y) => [applyTritwiseBinary(x, y, binaryTritOps.NSUM)]],
]);
class Sequence {
constructor(...items) {
this.items = items !== null && items !== void 0 ? items : [];
}
toString() {
return this.toArray().join(' ');
}
add(item) {
this.items.push(item);
}
size() {
return this.items.length;
}
get(index) {
return this.items[index];
}
set(index, value) {
this.items[index] = value;
}
concat(n) {
this.items = this.items.concat(n);
return this.items;
}
toArray() {
return this.items;
}
// New signs method
signs() {
const signArray = this.items.map(item => {
if (item > 0)
return 1;
else if (item < 0)
return -1;
return 0;
});
return new Sequence(...signArray); // Create a new Sequence with sign values
}
isNatural() {
return this.items.every(n => n >= 0);
}
difference() {
if (this.size() < 2) {
throw new Error("Difference requires at least two elements.");
}
const output = this.items.slice(1).map((item, index) => item - this.items[index]);
return new Sequence(...output);
}
cyclicalDifference() {
if (this.size() == 0) {
return new Sequence();
}
if (this.size() == 1) {
return new Sequence(...[0]);
}
const output = this.items.map((item, index) => {
return this.items[(index + 1) % this.size()] - item;
});
return new Sequence(...output);
}
antidifference(k) {
const output = new Array(this.size() + 1);
output[0] = k;
for (let i = 0; i < this.size(); i++) {
output[i + 1] = output[i] + this.items[i];
}
return new Sequence(...output);
}
cyclicalAntidifference(k) {
const output = new Array(this.size());
output[this.size() - 1] = k;
for (let i = 0; i < this.size(); i++) {
output[i] = output[(i - 1 + this.size()) % this.size()] + this.items[(i - 1 + this.size()) % this.size()];
}
return new Sequence(...output);
}
getSymmetries() {
const symmetries = [];
const n = this.size();
for (let i = 0; i < n * 2; i++) {
let axis = Math.floor(i / 2);
let found = true;
if (i % 2 === 0) {
for (let j = 0; j < 1 + Math.floor(n / 2); j++) {
if (this.get((axis + j) % n) !== this.get((n + axis - j) % n)) {
found = false;
break;
}
}
}
else {
for (let j = 0; j < 1 + Math.floor(n / 2); j++) {
if (this.get((axis + j + 1) % n) !== this.get((n + axis - j) % n)) {
found = false;
break;
}
}
}
if (found) {
symmetries.push(i / 2);
}
}
return symmetries;
}
static parse(s) {
const output = new Sequence();
const trimmed = s.trim().replace(/[,]/g, "");
let str0 = trimmed.startsWith('[') && trimmed.endsWith(']')
? trimmed.substring(1, trimmed.length - 1)
: trimmed;
const ss = str0.split(/\s+/);
for (const i of ss) {
if (i.trim() !== '') {
output.add(parseInt(i.trim()));
}
}
return output;
}
getMean() {
return this.sum() / this.size();
}
sum() {
return this.items.reduce((a, b) => a + b, 0);
}
getMin() {
return Math.min(...this.items);
}
getMax() {
return Math.max(...this.items);
}
rotate(n) {
const rotatedItems = [...this.items.slice(-n), ...this.items.slice(0, -n)];
const resultSeq = new Sequence();
for (const item of rotatedItems) {
resultSeq.add(item);
}
return resultSeq;
}
static fromArray(arr) {
const seq = new Sequence();
for (const item of arr) {
seq.add(item);
}
return seq;
}
// Frequency map
frequencyMap() {
const freqMap = new Map();
for (const item of this.items) {
freqMap.set(item, (freqMap.get(item) || 0) + 1);
}
return freqMap;
}
static genRnd(length, amp, sum, maxAmp, exclude0) {
if (length <= 1 || amp < 1 || maxAmp < 2 || (exclude0 && maxAmp < 2) ||
(Math.abs(sum) >= maxAmp)) {
throw new Error("Invalid parameters for random sequence generation.");
}
const sequence = new Sequence();
let currVal = sum;
sequence.add(currVal);
const possibleValues = [];
while (sequence.size() < length) {
possibleValues.length = 0;
for (let i = -amp; i <= amp; i++) {
if (Math.abs(currVal + i) < maxAmp && (i !== 0 || !exclude0)) {
possibleValues.push(i);
}
}
if (possibleValues.length === 0)
break;
const randomIndex = Math.floor(Math.random() * possibleValues.length);
currVal += possibleValues[randomIndex];
sequence.add(currVal);
}
return sequence;
}
// Calculate interval vector for a specific condition
static calculateIntervalVector(n, conditionFn) {
const m = Math.floor(n / 2);
const result = new Sequence();
for (let i = 1; i <= m; i++) {
let count = 0;
for (let j = 0; j < n; j++) {
if (conditionFn(j) && conditionFn((i + j) % n)) {
count++;
}
}
if (i === m && n % 2 === 0) {
count = Math.floor(count / 2);
}
result.add(count);
}
return result;
}
// Calculate interval vector for a boolean array
static calcIntervalVector(input) {
const n = input.length;
return this.calculateIntervalVector(n, (j) => input[j]);
}
// Calculate interval vector for a BitSet (presented as an array as TypeScript doesn't have BitSet)
static calcIntervalVectorBitSet(input, n) {
return this.calculateIntervalVector(n, (j) => input[j]);
}
// For distinct values in a sequence input
static calcIntervalVectorDistinct(sequence) {
const output = new Map();
const distinctValues = new Set(sequence.toArray());
for (const value of distinctValues) {
const booleanArray = sequence.toArray().map(item => item === value);
const intervalVector = this.calcIntervalVector(booleanArray);
output.set(value, intervalVector);
}
return output;
}
// Alternative overload to handle Integer[] while avoiding code duplication
static calcIntervalVectorInts(input) {
const sequence = new Sequence(...input);
return this.calcIntervalVectorDistinct(sequence);
}
static combine(combiner, operation, x, y) {
const o = new Sequence();
const operationFn = ops.get(operation);
const lcm = Numbers_1.Numbers.lcm(x.size(), y.size());
switch (combiner) {
case Combiner.Apply:
for (let i = 0; i < y.size(); i++) {
if (operationFn) {
let index = y.get(i);
while (index < 0)
index += x.size();
while (index >= x.size())
index -= x.size();
o.concat(operationFn(x.get(index), y.get(i % y.size())));
}
}
break;
case Combiner.Divisive:
for (let i = 0; i < lcm; i++) {
if (operationFn) {
o.concat(operationFn(x.get(i / (lcm / x.size()) >> 0), y.get(i / (lcm / y.size()) >> 0)));
}
}
break;
case Combiner.Recycle:
for (let i = 0; i < lcm; i++) {
if (operationFn) {
o.concat(operationFn(x.get(i % x.size()), y.get(i % y.size())));
}
}
break;
case Combiner.Product:
for (let i = 0; i < x.size(); i++) {
for (let j = 0; j < y.size(); j++) {
if (operationFn) {
o.concat(operationFn(x.get(i), y.get(j)));
}
}
}
break;
case Combiner.SwappedProduct:
for (let j = 0; j < y.size(); j++) {
for (let i = 0; i < x.size(); i++) {
if (operationFn) {
o.concat(operationFn(x.get(i), y.get(j)));
}
}
}
break;
case Combiner.Triangular:
for (let i = 0; i < x.size(); i++) {
for (let j = 0; j < y.size(); j++) {
if (j <= i && operationFn) {
o.concat(operationFn(x.get(i), y.get(j)));
}
}
}
break;
case Combiner.SwappedTriangular:
for (let j = 0; j < y.size(); j++) {
for (let i = 0; i < x.size(); i++) {
if (i <= j && operationFn) {
o.concat(operationFn(x.get(i), y.get(j)));
}
}
}
break;
case Combiner.Convolution:
for (let i = 0; i < x.size(); i++)
o.add(0);
for (let i = 0; i < o.size(); i++) {
for (let j = 0; j < y.size(); j++) {
if (operationFn) {
let v = operationFn(x.get(i), y.get(j));
for (let k = 0; k < v.length; k++) {
o.set((i + j + k) % o.size(), o.get((i + j + k) % o.size()) + v[k]);
}
}
}
}
break;
case Combiner.MixedRadix:
// This array will collect each combination (each row is an array of digits)
const result = [];
// Initialize the current combination with zeros
const current = new Array(x.size()).fill(0);
while (true) {
result.push([...current]);
if (current.every((value, i) => Math.abs(value) === Math.abs(x.get(i)) - 1)) {
break;
}
for (let i = 0; i < x.size(); i++) {
if (x.get(i) === 0)
break;
if (Math.abs(current[i]) < Math.abs(x.get(i)) - 1) {
if (x.get(i) < 0)
current[i]--;
if (x.get(i) > 0)
current[i]++;
break;
}
else {
current[i] = 0;
}
}
}
if (operationFn) {
const combined = result.map(row => row.map((value, index) => operationFn(value, y.get(index % y.size()))).reduce((a, b) => a + b.reduce((u, v) => u + v, 0), 0));
for (let z of combined)
o.add(z);
}
break;
}
return o;
}
;
}
exports.Sequence = Sequence;
;
//# sourceMappingURL=Sequence.js.map