UNPKG

ultra-mega-enumerator

Version:

Ultra Mega Enumerator is a lightweight library designed to enumerate various combinatorial objects.

599 lines 23.7 kB
"use strict"; 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