const Math = require('./bnmath'); const Glib = require('./Glib'); module.exports = class Vector { static fromString(string) { if (!string.startsWith('(') || !string.endsWith(')')) { throw new Error('invalid format'); } return new Vector( ...Glib.fromSplit(string.slice(1, -1), ',').map((i) => BigInt(i.trim())), ); } constructor(...v) { this.v = v.map((i) => { switch (typeof i) { case 'number': return BigInt(i); case 'bigint': return i; default: throw new Error('invalid input'); } }); } _check(v) { if (typeof v !== 'object' || !(v instanceof Vector)) { throw new Error('nope'); } if (this.len !== v.len) { throw new Error('mismatched length'); } } _resolve(v) { if (typeof v === 'number' || typeof v === 'bigint') { return new Vector(...this.v.map((e) => v)); } if (typeof v !== 'object' || !(v instanceof Vector)) { throw new Error('nope'); } if (this.len !== v.len) { throw new Error('mismatched length'); } return v; } static _resolveNumber(v) { if (typeof v === 'number') { return BigInt(v); } if (typeof v !== 'bigint') { throw new Error('nope'); } return v; } multiply(v) { v = this._resolve(v); return new Vector(...this.v.map((e, i) => e * v.v[i])); } add(v) { v = this._resolve(v); return new Vector(...this.v.map((e, i) => e + v.v[i])); } subtract(v) { v = this._resolve(v); return this.add(v.multiply(-1)); } remainder(v) { v = this._resolve(v); return new Vector(...this.v.map((e, i) => e % v.v[i])); } modulo(v) { v = this._resolve(v); return new Vector( ...this.v.map((e, i) => ((e % v.v[i]) + v.v[i]) % v.v[i]), ); } distance(v) { this._check(v); return this.v.glib .map((e, i) => { return Math.abs(e - v.v[i]); }) .sum(); } neighbors() { return new Glib( (function*(_this) { let permutations = 3n ** _this.length; const skipped = Math.parseInt('1'.repeat(_this.v.length), 3); for (let i = 0n; i < permutations; i++) { if (i === skipped) { continue; } yield _this.add( new Vector( ...Glib.fromIterable( i.toString(3).padStart(_this.v.length, '0'), ).map((i) => BigInt(i) - 1n), ), ); } })(this), ); } toArray() { return this.v.slice(); } set(place, value) { if (place > this.v.length) { throw new Error('out of bounds'); } value = Vector._resolveNumber(value); return new Vector(...this.v.chainSplice(place, 1, value)); } get length() { return BigInt(this.v.length); } get string() { return '(' + this.v.join(', ') + ')'; } };