125 lines
2.8 KiB
JavaScript
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(', ') + ')';
|
|
}
|
|
};
|