jsadvent/lib/Vector.js

125 lines
2.8 KiB
JavaScript

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(', ') + ')';
}
};