107 lines
2.5 KiB
JavaScript
107 lines
2.5 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;
|
||
|
}
|
||
|
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
|
||
|
.map((e, i) => {
|
||
|
return Math.abs(e + v.v[i]);
|
||
|
})
|
||
|
.reduce((a, b) => a + b);
|
||
|
}
|
||
|
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();
|
||
|
}
|
||
|
get length() {
|
||
|
return BigInt(this.v.length);
|
||
|
}
|
||
|
get string() {
|
||
|
return '(' + this.v.join(', ') + ')';
|
||
|
}
|
||
|
};
|